上篇文章Android socket 编程 实现消息推送(一)讲到socket编程的消息推送原理,现在我们来看看基于Android客户机socket编程实现消息推送的过程。

根据消息推送的原理图,我们的实现过程主要分为Server端和Client端,Server端采用Java的编程,而Client端则用Android编程。

所以在这里也分别创建了两个工程SocketServerSocketClient

1.SocketServer工程

我们先来看一下SocketMessage.java类:

[java] view plaincopy
  1. public class SocketMessage {
  2. public int to;//socketID,指发送给谁
  3. public int from;//socketID,指谁发送过来的
  4. public String msg;//消息内容
  5. public String time;//接收时间
  6. public SocketThread thread;//socketThread下面有介绍
  7. }

该类是一个消息类,用于表示消息是由谁发给谁的、消息内容是什么、接收时间是多少,只有几个属性,比较简单。

而MyServer.java类就相对比较多一些代码:

[java] view plaincopy
  1. package com.jimstin.server;
  2. import java.io.BufferedReader;
  3. import java.io.BufferedWriter;
  4. import java.io.InputStreamReader;
  5. import java.io.OutputStreamWriter;
  6. import java.net.ServerSocket;
  7. import java.net.Socket;
  8. import java.text.SimpleDateFormat;
  9. import java.util.ArrayList;
  10. import java.util.Date;
  11. import org.json.JSONObject;
  12. import com.jimstin.msg.SocketMessage;
  13. public class MyServer {
  14. private boolean isStartServer;
  15. private ServerSocket mServer;
  16. /**
  17. * 消息队列,用于保存SocketServer接收来自于客户机(手机端)的消息
  18. */
  19. private ArrayList<SocketMessage> mMsgList = new ArrayList<SocketMessage>();
  20. /**
  21. * 线程队列,用于接收消息。每个客户机拥有一个线程,每个线程只接收发送给自己的消息
  22. */
  23. private ArrayList<SocketThread> mThreadList = new ArrayList<SocketThread>();
  24. /**
  25. * 开启SocketServer
  26. */
  27. private void startSocket() {
  28. try {
  29. isStartServer = true;
  30. int prot = 2000;//端口可以自己设置,但要和Client端的端口保持一致
  31. mServer = new ServerSocket(prot);//创建一个ServerSocket
  32. System.out.println("启动server,端口:"+prot);
  33. Socket socket = null;
  34. int socketID = 0;//Android(SocketClient)客户机的唯一标志,每个socketID表示一个Android客户机
  35. //开启发送消息线程
  36. startSendMessageThread();
  37. //用一个循环来检测是否有新的客户机加入
  38. while(isStartServer) {
  39. //accept()方法是一个阻塞的方法,调用该方法后,
  40. //该线程会一直阻塞,直到有新的客户机加入,代码才会继续往下走
  41. socket = mServer.accept();
  42. //有新的客户机加入后,则创建一个新的SocketThread线程对象
  43. SocketThread thread = new SocketThread(socket, socketID++);
  44. thread.start();
  45. //将该线程添加到线程队列
  46. mThreadList.add(thread);
  47. }
  48. } catch (Exception e) {
  49. e.printStackTrace();
  50. }
  51. }
  52. /**
  53. * 开启推送消息线程,如果mMsgList中有SocketMessage,则把该消息推送到Android客户机
  54. */
  55. public void startSendMessageThread() {
  56. new Thread(){
  57. @Override
  58. public void run() {
  59. super.run();
  60. try {
  61. /*如果isStartServer=true,则说明SocketServer已启动,
  62. 用一个循环来检测消息队列中是否有消息,如果有,则推送消息到相应的客户机*/
  63. while(isStartServer) {
  64. //判断消息队列中的长度是否大于0,大于0则说明消息队列不为空
  65. if(mMsgList.size() > 0) {
  66. //读取消息队列中的第一个消息
  67. SocketMessage from = mMsgList.get(0);
  68. for(SocketThread to : mThreadList) {
  69. if(to.socketID == from.to) {
  70. BufferedWriter writer = to.writer;
  71. JSONObject json = new JSONObject();
  72. json.put("from", from.from);
  73. json.put("msg", from.msg);
  74. json.put("time", from.time);
  75. //writer写进json中的字符串数据,末尾记得加换行符:"\n",否则在客户机端无法识别
  76. //因为BufferedReader.readLine()方法是根据换行符来读取一行的
  77. writer.write(json.toString()+"\n");
  78. //调用flush()方法,刷新流缓冲,把消息推送到手机端
  79. writer.flush();
  80. System.out.println("推送消息成功:"+from.msg+">> to socketID:"+from.to);
  81. break;
  82. }
  83. }
  84. //每推送一条消息之后,就要在消息队列中移除该消息
  85. mMsgList.remove(0);
  86. }
  87. Thread.sleep(200);
  88. }
  89. } catch (Exception e) {
  90. e.printStackTrace();
  91. }
  92. }
  93. }.start();
  94. }
  95. /**
  96. * 定义一个SocketThread类,用于接收消息
  97. *
  98. */
  99. public class SocketThread extends Thread {
  100. public int socketID;
  101. public Socket socket;//Socket用于获取输入流、输出流
  102. public BufferedWriter writer;//BufferedWriter 用于推送消息
  103. public BufferedReader reader;//BufferedReader 用于接收消息
  104. public SocketThread(Socket socket, int count) {
  105. socketID = count;
  106. this.socket = socket;
  107. System.out.println("新增一台客户机,socketID:"+socketID);
  108. }
  109. @Override
  110. public void run() {
  111. super.run();
  112. try {
  113. //初始化BufferedReader
  114. reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8"));
  115. //初始化BufferedWriter
  116. writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "utf-8"));
  117. //如果isStartServer=true,则说明SocketServer已经启动,
  118. //现在需要用一个循环来不断接收来自客户机的消息,并作其他处理
  119. while(isStartServer) {
  120. //先判断reader是否已经准备好
  121. if(reader.ready()) {
  122. /*读取一行字符串,读取的内容来自于客户机
  123. reader.readLine()方法是一个阻塞方法,
  124. 从调用这个方法开始,该线程会一直处于阻塞状态,
  125. 直到接收到新的消息,代码才会往下走*/
  126. String data = reader.readLine();
  127. //讲data作为json对象的内容,创建一个json对象
  128. JSONObject json = new JSONObject(data);
  129. //创建一个SocketMessage对象,用于接收json中的数据
  130. SocketMessage msg = new SocketMessage();
  131. msg.to = json.getInt("to");
  132. msg.msg = json.getString("msg");
  133. msg.from = socketID;
  134. msg.time = getTime(System.currentTimeMillis());
  135. //接收到一条消息后,将该消息添加到消息队列mMsgList
  136. mMsgList.add(msg);
  137. System.out.println("收到一条消息:"+json.getString("msg")+" >>>> to socketID:"+json.getInt("to"));
  138. }
  139. //睡眠100ms,每100ms检测一次是否有接收到消息
  140. Thread.sleep(100);
  141. }
  142. } catch (Exception e) {
  143. e.printStackTrace();
  144. }
  145. }
  146. }
  147. /**
  148. * 获取指定格式的时间字符串,通过毫秒转换日期
  149. * @param millTime
  150. */
  151. private String getTime(long millTime) {
  152. Date d = new Date(millTime);
  153. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  154. return sdf.format(d);
  155. }
  156. public static void main(String[] args) {
  157. MyServer server = new MyServer();
  158. server.startSocket();
  159. }
  160. }

2.SocketClient工程

该工程是一个Android的工程,只有一个MainActivity.java和activity_main.xml文件,

先看一下activity_main.xml布局文件:

[html] view plaincopy
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. tools:context=".MainActivity"
  6. android:orientation="vertical" >
  7. <LinearLayout
  8. android:layout_width="match_parent"
  9. android:layout_height="wrap_content"
  10. android:orientation="horizontal">
  11. <EditText
  12. android:id="@+id/ip_edt"
  13. android:layout_width="0dp"
  14. android:layout_height="wrap_content"
  15. android:layout_weight="1"
  16. android:hint="ip"
  17. android:text="172.16.1.200"/>
  18. <EditText
  19. android:id="@+id/port_edt"
  20. android:layout_width="0dp"
  21. android:layout_height="wrap_content"
  22. android:layout_weight="1"
  23. android:hint="port"
  24. android:text="2000"/>
  25. </LinearLayout>
  26. <Button
  27. android:id="@+id/start_btn"
  28. android:layout_width="match_parent"
  29. android:layout_height="wrap_content"
  30. android:text="start"/>
  31. <EditText
  32. android:id="@+id/socket_id_edt"
  33. android:layout_width="match_parent"
  34. android:layout_height="wrap_content"
  35. android:hint="socketID"/>
  36. <EditText
  37. android:id="@+id/msg_edt"
  38. android:layout_width="match_parent"
  39. android:layout_height="wrap_content"
  40. android:minLines="5"
  41. android:hint="content"
  42. android:gravity="top"
  43. />
  44. <Button
  45. android:id="@+id/send_btn"
  46. android:layout_width="match_parent"
  47. android:layout_height="wrap_content"
  48. android:text="send"/>
  49. <TextView
  50. android:id="@+id/console_txt"
  51. android:layout_width="match_parent"
  52. android:layout_height="0dp"
  53. android:layout_weight="1"/>
  54. <Button
  55. android:id="@+id/clear_btn"
  56. android:layout_width="match_parent"
  57. android:layout_height="wrap_content"
  58. android:text="clear"/>
  59. </LinearLayout>

效果图:

MainActivity.java类:

[java] view plaincopy
  1. package com.jimstin.socketclient;
  2. import java.io.BufferedReader;
  3. import java.io.BufferedWriter;
  4. import java.io.IOException;
  5. import java.io.InputStreamReader;
  6. import java.io.OutputStreamWriter;
  7. import java.net.Socket;
  8. import java.net.UnknownHostException;
  9. import java.text.SimpleDateFormat;
  10. import java.util.Date;
  11. import org.json.JSONObject;
  12. import com.tencent.stat.MtaSDkException;
  13. import com.tencent.stat.StatConfig;
  14. import com.tencent.stat.StatService;
  15. import android.R.integer;
  16. import android.os.AsyncTask;
  17. import android.os.Bundle;
  18. import android.os.Handler;
  19. import android.os.Message;
  20. import android.util.Log;
  21. import android.view.View;
  22. import android.view.View.OnClickListener;
  23. import android.widget.EditText;
  24. import android.widget.TextView;
  25. import android.widget.Toast;
  26. import android.app.Activity;
  27. public class MainActivity extends Activity implements OnClickListener {
  28. private EditText mIPEdt, mPortEdt, mSocketIDEdt, mMessageEdt;
  29. private static TextView mConsoleTxt;
  30. private static StringBuffer mConsoleStr = new StringBuffer();
  31. private Socket mSocket;
  32. private boolean isStartRecieveMsg;
  33. private SocketHandler mHandler;
  34. protected BufferedReader mReader;//BufferedWriter 用于推送消息
  35. protected BufferedWriter mWriter;//BufferedReader 用于接收消息
  36. @Override
  37. protected void onCreate(Bundle savedInstanceState) {
  38. super.onCreate(savedInstanceState);
  39. setContentView(R.layout.activity_main);
  40. initView();
  41. }
  42. private void initView() {
  43. mIPEdt = (EditText) findViewById(R.id.ip_edt);
  44. mPortEdt = (EditText) findViewById(R.id.port_edt);
  45. mSocketIDEdt = (EditText) findViewById(R.id.socket_id_edt);
  46. mMessageEdt = (EditText) findViewById(R.id.msg_edt);
  47. mConsoleTxt = (TextView) findViewById(R.id.console_txt);
  48. findViewById(R.id.start_btn).setOnClickListener(this);
  49. findViewById(R.id.send_btn).setOnClickListener(this);
  50. findViewById(R.id.clear_btn).setOnClickListener(this);
  51. mHandler = new SocketHandler();
  52. }
  53. /**
  54. * 初始化socket
  55. */
  56. private void initSocket() {
  57. //新建一个线程,用于初始化socket和检测是否有接收到新的消息
  58. Thread thread = new Thread(new Runnable() {
  59. @Override
  60. public void run() {
  61. String ip = mIPEdt.getText().toString();//IP
  62. int port = Integer.parseInt(mPortEdt.getText().toString());//Socket
  63. try {
  64. isStartRecieveMsg = true;
  65. mSocket = new Socket(ip, port);
  66. mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream(), "utf-8"));
  67. mWriter = new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream(), "utf-8"));
  68. while(isStartRecieveMsg) {
  69. if(mReader.ready()) {
  70. /*读取一行字符串,读取的内容来自于客户机
  71. reader.readLine()方法是一个阻塞方法,
  72. 从调用这个方法开始,该线程会一直处于阻塞状态,
  73. 直到接收到新的消息,代码才会往下走*/
  74. String data = mReader.readLine();
  75. //handler发送消息,在handleMessage()方法中接收
  76. mHandler.obtainMessage(0, data).sendToTarget();
  77. }
  78. Thread.sleep(200);
  79. }
  80. mWriter.close();
  81. mReader.close();
  82. mSocket.close();
  83. } catch (Exception e) {
  84. e.printStackTrace();
  85. }
  86. }
  87. });
  88. thread.start();
  89. }
  90. @Override
  91. public void onClick(View v) {
  92. switch (v.getId()) {
  93. case R.id.send_btn:
  94. send();
  95. break;
  96. case R.id.clear_btn:
  97. mConsoleStr.delete(0, mConsoleStr.length());
  98. mConsoleTxt.setText(mConsoleStr.toString());
  99. break;
  100. case R.id.start_btn:
  101. if(!isStartRecieveMsg) {
  102. initSocket();
  103. }
  104. break;
  105. default:
  106. break;
  107. }
  108. }
  109. /**
  110. * 发送
  111. */
  112. private void send() {
  113. new AsyncTask<String, Integer, String>() {
  114. @Override
  115. protected String doInBackground(String... params) {
  116. sendMsg();
  117. return null;
  118. }
  119. }.execute();
  120. }
  121. /**
  122. * 发送消息
  123. */
  124. protected void sendMsg() {
  125. try {
  126. String socketID = mSocketIDEdt.getText().toString().trim();
  127. String msg = mMessageEdt.getText().toString().trim();
  128. JSONObject json = new JSONObject();
  129. json.put("to", socketID);
  130. json.put("msg", msg);
  131. mWriter.write(json.toString()+"\n");
  132. mWriter.flush();
  133. mConsoleStr.append("我:" +msg+"   "+getTime(System.currentTimeMillis())+"\n");
  134. mConsoleTxt.setText(mConsoleStr);
  135. } catch (Exception e) {
  136. e.printStackTrace();
  137. }
  138. }
  139. static class SocketHandler extends Handler {
  140. @Override
  141. public void handleMessage(Message msg) {
  142. // TODO Auto-generated method stub
  143. super.handleMessage(msg);
  144. switch (msg.what) {
  145. case 0:
  146. try {
  147. //将handler中发送过来的消息创建json对象
  148. JSONObject json = new JSONObject((String)msg.obj);
  149. mConsoleStr.append(json.getString("from")+":" +json.getString("msg")+"   "+getTime(System.currentTimeMillis())+"\n");
  150. //将json数据显示在TextView中
  151. mConsoleTxt.setText(mConsoleStr);
  152. } catch (Exception e) {
  153. e.printStackTrace();
  154. }
  155. break;
  156. default:
  157. break;
  158. }
  159. }
  160. }
  161. @Override
  162. public void onBackPressed() {
  163. super.onBackPressed();
  164. isStartRecieveMsg = false;
  165. }
  166. private static String getTime(long millTime) {
  167. Date d = new Date(millTime);
  168. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  169. return sdf.format(d);
  170. }
  171. }

以上代码的注释都比较详细,就不再多说了。

资源下载地址:http://download.csdn.NET/detail/zhangjm_123/8258019

注意:先把Android端的apk分别安装到两台手机上面,再运行SocketServer,点击SocketClient的Start,在SocketServer的控制台上面就可以看到有新的客户机增加了(确保IP地址和端口的正确前提下)。然后输入socketID(socketID表示Android客户机的一个账号,就像QQ号一样,从0开始,一个socketID表示一个客户机)和content,点击send就可以发送消息了。

效果图请见Android socket 编程 实现消息推送(一)

有问题的欢迎留言。

5
0

Android socket 编程 实现消息推送(二)相关推荐

  1. Android socket 编程 实现消息推送(一)

    最近用socket写了一个消息推送的demo,在这里和大家分享一下. 主要实现了:一台手机向另外一台手机发送消息,这两台手机可以随时自由发送文本消息进行通信,类似我们常用的QQ. 效果图        ...

  2. Android socket 编程 实现消息推送

    最近用socket写了一个消息推送的demo,在这里和大家分享一下. 主要实现了:一台手机向另外一台手机发送消息,这两台手机可以随时自由发送文本消息进行通信,类似我们常用的QQ. 效果图:    原理 ...

  3. Android:Umeng(友盟)消息推送(二)

    在已集成友盟统计的情况下:Android:Umeng(友盟)数据统计(一) 第一步: 个人中心---U-Push(消息推送)---添加新应用---从已有应用中添加  如图: 获得Appkey和secr ...

  4. java android消息推送_Android中使用socket通信实现消息推送的方法详解

    原理最近用socket写了一个消息推送的demo,在这里和大家分享一下. 主要实现了:一台手机向另外一台手机发送消息,这两台手机可以随时自由发送文本消息进行通信,类似我们常用的QQ. 效果图: 原理: ...

  5. 【转】android系统的APP消息推送机制

    原文:https://www.jianshu.com/p/f898a2c02b05 参考文章: http://blog.csdn.net/carson_ho/article/details/52862 ...

  6. Android集成阿里云消息推送的方法步骤

    一 创建App应用 1.1 在控制台发(https://mhub.console.aliyun.com)的App列表页,点击页面产品列表中"添加产品"的图标即可创建一个新的产品(产 ...

  7. Android端消息推送总结:实现原理、心跳保活、遇到的问题等

    前言 最近研究Android推送的实现, 研究了两天一夜, 有了一点收获, 写下来既为了分享, 也为了吐槽. 需要说明的是有些东西偏底层硬件和通信行业, 我对这些一窍不通, 只能说说自己的理解. 为什 ...

  8. 浅谈iOS和Android后台实时消息推送的原理和区别

    http://www.52im.net/thread-286-1-1.html 前言 iOS和Android上的实时消息推送差异很大,往小了说是技术实现的差异,往大了说是系统实现理念的不同.实时消息推 ...

  9. Android 项目必备(三十八)-->APP 消息推送

    文章目录 前言 推送的实现方式 1. C2DM 2. 轮询 3. SMS信令推送 4. MQTT协议 5. XMPP协议 6. 使用第三方平台 Android 中 MQTT 的使用 1. 集成 2. ...

最新文章

  1. 使用AI画一个冠状病毒
  2. java音频库_Java是否为音频_synthesis_内置了库?
  3. wap开发中取到真实的手机号码
  4. 软件工程方法学要素含义_日期时间数据的要素工程
  5. ECCV 2020 | CV “造车”,生成内容一致的车辆数据集 |
  6. Object-C---gt;Swift之(一)元组(tuple)类型
  7. python ggplot为什么不能取代matplotlib_为什么geom_bar()不会像python ggplot中那样更改填充颜色?...
  8. iOS开发:Pokemon Go试玩,未越狱的iPhone伪造GPS定位信息
  9. 联想外接键盘fn热键取消
  10. KVM地址翻译流程及EPT页表的建立过程
  11. 辞职时被领导挽留,要不要留下?
  12. php web helloworld,webim_server.php
  13. Inferior 1 (process 663) exited with code 0177
  14. python模拟登录12306_python模拟登录12306缺少cookies
  15. Codeforces Round #672 (Div. 2) C2 - Pokémon Army (hard version)(贪心,维护变化值)
  16. 欧拉定理、快速幂与逆元
  17. C/C++音视频高级开发-开源流媒体服务器SRS环境搭建
  18. 《锋利的jQuery》读书要点笔记7——制作商城网页:网站脚本
  19. SpringBoot 实现 Office 各种格式在线预览(详细教程,包教包会)
  20. 26对称矩阵及正定性

热门文章

  1. 16.编译错误Unknown CMake command “check_symbol_exists“解决
  2. VISP视觉库框架详细解释
  3. MFC创建属性表单“所需资源不存在”错误解决方法
  4. Halcon模板轮廓坐标点获取
  5. win7发现不了无线网络_win10系统间设置共享文件夹后“网络”选项下仍然无任何文件(即发现不了共享电脑)...
  6. hive创建mysql表,hiveMysql创建、修改、删除字段/表
  7. arm云教室服务器_成都凌点科技告诉你ARM集群服务器适合的应用场景有哪些
  8. Web 开发学习笔记(1) --- 搭建你的第一个 Web Server
  9. Keepalived + LVS-DR搭建高可用Web服务器集群
  10. openlayers 根据style设置显示级别并在字体加背景框