Android socket 编程 实现消息推送(二)
来源:互联网 发布:validator.js 编辑:程序博客网 时间:2024/06/03 19:04
上篇文章Android socket 编程 实现消息推送(一)讲到socket编程的消息推送原理,现在我们来看看基于Android客户机socket编程实现消息推送的过程。
根据消息推送的原理图,我们的实现过程主要分为Server端和Client端,Server端采用Java的编程,而Client端则用Android编程。
所以在这里也分别创建了两个工程SocketServer和SocketClient
1.SocketServer工程
我们先来看一下SocketMessage.java类:
- public class SocketMessage {
- public int to;//socketID,指发送给谁
- public int from;//socketID,指谁发送过来的
- public String msg;//消息内容
- public String time;//接收时间
- public SocketThread thread;//socketThread下面有介绍
- }
该类是一个消息类,用于表示消息是由谁发给谁的、消息内容是什么、接收时间是多少,只有几个属性,比较简单。
而MyServer.java类就相对比较多一些代码:
- package com.jimstin.server;
- import java.io.BufferedReader;
- import java.io.BufferedWriter;
- import java.io.InputStreamReader;
- import java.io.OutputStreamWriter;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.text.SimpleDateFormat;
- import java.util.ArrayList;
- import java.util.Date;
- import org.json.JSONObject;
- import com.jimstin.msg.SocketMessage;
- public class MyServer {
- private boolean isStartServer;
- private ServerSocket mServer;
- /**
- * 消息队列,用于保存SocketServer接收来自于客户机(手机端)的消息
- */
- private ArrayList<SocketMessage> mMsgList = new ArrayList<SocketMessage>();
- /**
- * 线程队列,用于接收消息。每个客户机拥有一个线程,每个线程只接收发送给自己的消息
- */
- private ArrayList<SocketThread> mThreadList = new ArrayList<SocketThread>();
- /**
- * 开启SocketServer
- */
- private void startSocket() {
- try {
- isStartServer = true;
- int prot = 2000;//端口可以自己设置,但要和Client端的端口保持一致
- mServer = new ServerSocket(prot);//创建一个ServerSocket
- System.out.println("启动server,端口:"+prot);
- Socket socket = null;
- int socketID = 0;//Android(SocketClient)客户机的唯一标志,每个socketID表示一个Android客户机
- //开启发送消息线程
- startSendMessageThread();
- //用一个循环来检测是否有新的客户机加入
- while(isStartServer) {
- //accept()方法是一个阻塞的方法,调用该方法后,
- //该线程会一直阻塞,直到有新的客户机加入,代码才会继续往下走
- socket = mServer.accept();
- //有新的客户机加入后,则创建一个新的SocketThread线程对象
- SocketThread thread = new SocketThread(socket, socketID++);
- thread.start();
- //将该线程添加到线程队列
- mThreadList.add(thread);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * 开启推送消息线程,如果mMsgList中有SocketMessage,则把该消息推送到Android客户机
- */
- public void startSendMessageThread() {
- new Thread(){
- @Override
- public void run() {
- super.run();
- try {
- /*如果isStartServer=true,则说明SocketServer已启动,
- 用一个循环来检测消息队列中是否有消息,如果有,则推送消息到相应的客户机*/
- while(isStartServer) {
- //判断消息队列中的长度是否大于0,大于0则说明消息队列不为空
- if(mMsgList.size() > 0) {
- //读取消息队列中的第一个消息
- SocketMessage from = mMsgList.get(0);
- for(SocketThread to : mThreadList) {
- if(to.socketID == from.to) {
- BufferedWriter writer = to.writer;
- JSONObject json = new JSONObject();
- json.put("from", from.from);
- json.put("msg", from.msg);
- json.put("time", from.time);
- //writer写进json中的字符串数据,末尾记得加换行符:"\n",否则在客户机端无法识别
- //因为BufferedReader.readLine()方法是根据换行符来读取一行的
- writer.write(json.toString()+"\n");
- //调用flush()方法,刷新流缓冲,把消息推送到手机端
- writer.flush();
- System.out.println("推送消息成功:"+from.msg+">> to socketID:"+from.to);
- break;
- }
- }
- //每推送一条消息之后,就要在消息队列中移除该消息
- mMsgList.remove(0);
- }
- Thread.sleep(200);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }.start();
- }
- /**
- * 定义一个SocketThread类,用于接收消息
- *
- */
- public class SocketThread extends Thread {
- public int socketID;
- public Socket socket;//Socket用于获取输入流、输出流
- public BufferedWriter writer;//BufferedWriter 用于推送消息
- public BufferedReader reader;//BufferedReader 用于接收消息
- public SocketThread(Socket socket, int count) {
- socketID = count;
- this.socket = socket;
- System.out.println("新增一台客户机,socketID:"+socketID);
- }
- @Override
- public void run() {
- super.run();
- try {
- //初始化BufferedReader
- reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8"));
- //初始化BufferedWriter
- writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "utf-8"));
- //如果isStartServer=true,则说明SocketServer已经启动,
- //现在需要用一个循环来不断接收来自客户机的消息,并作其他处理
- while(isStartServer) {
- //先判断reader是否已经准备好
- if(reader.ready()) {
- /*读取一行字符串,读取的内容来自于客户机
- reader.readLine()方法是一个阻塞方法,
- 从调用这个方法开始,该线程会一直处于阻塞状态,
- 直到接收到新的消息,代码才会往下走*/
- String data = reader.readLine();
- //讲data作为json对象的内容,创建一个json对象
- JSONObject json = new JSONObject(data);
- //创建一个SocketMessage对象,用于接收json中的数据
- SocketMessage msg = new SocketMessage();
- msg.to = json.getInt("to");
- msg.msg = json.getString("msg");
- msg.from = socketID;
- msg.time = getTime(System.currentTimeMillis());
- //接收到一条消息后,将该消息添加到消息队列mMsgList
- mMsgList.add(msg);
- System.out.println("收到一条消息:"+json.getString("msg")+" >>>> to socketID:"+json.getInt("to"));
- }
- //睡眠100ms,每100ms检测一次是否有接收到消息
- Thread.sleep(100);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- /**
- * 获取指定格式的时间字符串,通过毫秒转换日期
- * @param millTime
- */
- private String getTime(long millTime) {
- Date d = new Date(millTime);
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- return sdf.format(d);
- }
- public static void main(String[] args) {
- MyServer server = new MyServer();
- server.startSocket();
- }
- }
2.SocketClient工程
该工程是一个Android的工程,只有一个MainActivity.java和activity_main.xml文件,
先看一下activity_main.xml布局文件:
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".MainActivity"
- android:orientation="vertical" >
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <EditText
- android:id="@+id/ip_edt"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:hint="ip"
- android:text="172.16.1.200"/>
- <EditText
- android:id="@+id/port_edt"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:hint="port"
- android:text="2000"/>
- </LinearLayout>
- <Button
- android:id="@+id/start_btn"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="start"/>
- <EditText
- android:id="@+id/socket_id_edt"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="socketID"/>
- <EditText
- android:id="@+id/msg_edt"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minLines="5"
- android:hint="content"
- android:gravity="top"
- />
- <Button
- android:id="@+id/send_btn"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="send"/>
- <TextView
- android:id="@+id/console_txt"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"/>
- <Button
- android:id="@+id/clear_btn"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="clear"/>
- </LinearLayout>
效果图:
MainActivity.java类:
- package com.jimstin.socketclient;
- import java.io.BufferedReader;
- import java.io.BufferedWriter;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.OutputStreamWriter;
- import java.net.Socket;
- import java.net.UnknownHostException;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import org.json.JSONObject;
- import com.tencent.stat.MtaSDkException;
- import com.tencent.stat.StatConfig;
- import com.tencent.stat.StatService;
- import android.R.integer;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.util.Log;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.EditText;
- import android.widget.TextView;
- import android.widget.Toast;
- import android.app.Activity;
- public class MainActivity extends Activity implements OnClickListener {
- private EditText mIPEdt, mPortEdt, mSocketIDEdt, mMessageEdt;
- private static TextView mConsoleTxt;
- private static StringBuffer mConsoleStr = new StringBuffer();
- private Socket mSocket;
- private boolean isStartRecieveMsg;
- private SocketHandler mHandler;
- protected BufferedReader mReader;//BufferedWriter 用于推送消息
- protected BufferedWriter mWriter;//BufferedReader 用于接收消息
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- initView();
- }
- private void initView() {
- mIPEdt = (EditText) findViewById(R.id.ip_edt);
- mPortEdt = (EditText) findViewById(R.id.port_edt);
- mSocketIDEdt = (EditText) findViewById(R.id.socket_id_edt);
- mMessageEdt = (EditText) findViewById(R.id.msg_edt);
- mConsoleTxt = (TextView) findViewById(R.id.console_txt);
- findViewById(R.id.start_btn).setOnClickListener(this);
- findViewById(R.id.send_btn).setOnClickListener(this);
- findViewById(R.id.clear_btn).setOnClickListener(this);
- mHandler = new SocketHandler();
- }
- /**
- * 初始化socket
- */
- private void initSocket() {
- //新建一个线程,用于初始化socket和检测是否有接收到新的消息
- Thread thread = new Thread(new Runnable() {
- @Override
- public void run() {
- String ip = mIPEdt.getText().toString();//IP
- int port = Integer.parseInt(mPortEdt.getText().toString());//Socket
- try {
- isStartRecieveMsg = true;
- mSocket = new Socket(ip, port);
- mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream(), "utf-8"));
- mWriter = new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream(), "utf-8"));
- while(isStartRecieveMsg) {
- if(mReader.ready()) {
- /*读取一行字符串,读取的内容来自于客户机
- reader.readLine()方法是一个阻塞方法,
- 从调用这个方法开始,该线程会一直处于阻塞状态,
- 直到接收到新的消息,代码才会往下走*/
- String data = mReader.readLine();
- //handler发送消息,在handleMessage()方法中接收
- mHandler.obtainMessage(0, data).sendToTarget();
- }
- Thread.sleep(200);
- }
- mWriter.close();
- mReader.close();
- mSocket.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- });
- thread.start();
- }
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.send_btn:
- send();
- break;
- case R.id.clear_btn:
- mConsoleStr.delete(0, mConsoleStr.length());
- mConsoleTxt.setText(mConsoleStr.toString());
- break;
- case R.id.start_btn:
- if(!isStartRecieveMsg) {
- initSocket();
- }
- break;
- default:
- break;
- }
- }
- /**
- * 发送
- */
- private void send() {
- new AsyncTask<String, Integer, String>() {
- @Override
- protected String doInBackground(String... params) {
- sendMsg();
- return null;
- }
- }.execute();
- }
- /**
- * 发送消息
- */
- protected void sendMsg() {
- try {
- String socketID = mSocketIDEdt.getText().toString().trim();
- String msg = mMessageEdt.getText().toString().trim();
- JSONObject json = new JSONObject();
- json.put("to", socketID);
- json.put("msg", msg);
- mWriter.write(json.toString()+"\n");
- mWriter.flush();
- mConsoleStr.append("我:" +msg+" "+getTime(System.currentTimeMillis())+"\n");
- mConsoleTxt.setText(mConsoleStr);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- static class SocketHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- // TODO Auto-generated method stub
- super.handleMessage(msg);
- switch (msg.what) {
- case 0:
- try {
- //将handler中发送过来的消息创建json对象
- JSONObject json = new JSONObject((String)msg.obj);
- mConsoleStr.append(json.getString("from")+":" +json.getString("msg")+" "+getTime(System.currentTimeMillis())+"\n");
- //将json数据显示在TextView中
- mConsoleTxt.setText(mConsoleStr);
- } catch (Exception e) {
- e.printStackTrace();
- }
- break;
- default:
- break;
- }
- }
- }
- @Override
- public void onBackPressed() {
- super.onBackPressed();
- isStartRecieveMsg = false;
- }
- private static String getTime(long millTime) {
- Date d = new Date(millTime);
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- return sdf.format(d);
- }
- }
以上代码的注释都比较详细,就不再多说了。
资源下载地址: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 编程 实现消息推送(二)
- Android socket 编程 实现消息推送(二)
- Android socket 编程 实现消息推送(二)
- Android socket 编程 实现消息推送
- Android socket 编程 实现消息推送(一)
- Android socket 编程 实现消息推送(一)
- Android学习笔记三十五:socket 编程 实现消息推送
- Socket实现消息推送
- java socket编程(1)——利用socket实现聊天之消息推送
- android消息推送实现
- Android消息推送(主: XMPP协议实现Android推送)
- Android中实现消息推送(JPush)-极光推送
- 利用 socket.io 实现消息实时推送
- Android百度云推送实现消息推送
- android中实现消息推送
- android中实现消息推送
- Android之消息推送实现
- Android之消息推送实现
- iOS之tableView左划显示多个按钮
- Tiny210(S5PV210) U-BOOT(一)----启动过程
- Android -- 小试AIDL
- 洛谷 P1604 B进制星球
- bootstrap表单验证
- Android socket 编程 实现消息推送(二)
- Android NDK开发之引用纯C库文件
- Android设置上下边框,或者左右边框
- nc传送文件
- Hadoop入门
- Unity常用脚本类的继承关系
- python学习之调试(Debugging)
- VS2010控件之COMBOX
- 关于版本控制发展历程