Android应用socket即时通讯的实现

来源:互联网 发布:nginx源码 编辑:程序博客网 时间:2024/05/19 05:39

一、服务器

思路:

首先创建服务器,用一个死循环等候若干个客户端的连接。一旦有客户端连接,就把客户端添加到集合当中,并且启动一个新的线程来保持长连接,监控客户端发来的信息。一旦接收到有客户端发来的信息,就进行包装后遍历集合,把包装好的信息发送给每一个客户端。

代码如下:

[java] view plain copy
  1. /** 
  2.  * Tcp通信服务器 
  3.  * @author Devin Chen 
  4.  * 
  5.  */  
  6. public class CSServer {  
  7.     private static final int PORT = 8888;  
  8.     private List<Socket> mClientList = new ArrayList<Socket>();  
  9.     private ServerSocket server = null;  
  10.     private ExecutorService mExecutors = null// 线程池对象  
  11.   
  12.     public static void main(String[] args) {  
  13.         new CSServer();  
  14.     }  
  15.   
  16.     /** 
  17.      * 构造方法:任务是启动服务器,等待客户端连接 
  18.      */  
  19.     public CSServer() {  
  20.         try {  
  21.             server = new ServerSocket(PORT);  
  22.             mExecutors = Executors.newCachedThreadPool(); // 创建线程池  
  23.             System.out.println("服务器已启动,等待客户端连接...");  
  24.             Socket client = null;  
  25.             /* 
  26.              * 用死循环等待多个客户端的连接,连接一个就启动一个线程进行管理 
  27.              */  
  28.             while (true) {  
  29.                 client = server.accept();  
  30.                 // 把客户端放入集合中  
  31.                 mClientList.add(client);  
  32.                 mExecutors.execute(new Service(client)); // 启动一个线程,用以守候从客户端发来的消息  
  33.             }  
  34.         } catch (Exception e) {  
  35.             e.printStackTrace();  
  36.         }  
  37.     }  
  38.   
  39.     class Service implements Runnable {  
  40.         private Socket socket;  
  41.         private BufferedReader in = null;  
  42.         private String message = "";  
  43.   
  44.         public Service(Socket socket) {  
  45.             this.socket = socket;  
  46.             try {  
  47.                 in = new BufferedReader(new InputStreamReader(  
  48.                         socket.getInputStream()));// 获得输入流对象  
  49.                 // 客户端只要一连到服务器,便发送连接成功的信息  
  50.                 message = "服务器地址:" + this.socket.getInetAddress();  
  51.                 this.sendMessage(message);  
  52.                 message = "当前连接总数:" + mClientList.size();  
  53.                 this.sendMessage(message);  
  54.             } catch (IOException e) {  
  55.                 e.printStackTrace();  
  56.             }  
  57.   
  58.         }  
  59.   
  60.         @Override  
  61.         public void run() {  
  62.             try {  
  63.                 while (true) {  
  64.                     if ((message = in.readLine()) != null) {  
  65.                         // 当客户端发送的信息为:exit时,关闭连接  
  66.                         if (message.equals("exit")) {  
  67.                             closeSocket();  
  68.                             break;  
  69.                         } else {  
  70.                             // 接收客户端发过来的信息message,然后转发给客户端。  
  71.                             message = socket.getInetAddress() + ":" + message;  
  72.                             this.sendMessage(message);  
  73.                         }  
  74.                     }  
  75.                 }  
  76.             } catch (Exception e) {  
  77.                 e.printStackTrace();  
  78.             }  
  79.         }  
  80.   
  81.         /** 
  82.          * 关闭客户端 
  83.          *  
  84.          * @throws IOException 
  85.          */  
  86.         public void closeSocket() throws IOException {  
  87.             mClientList.remove(socket);  
  88.             in.close();  
  89.             message = "主机:" + socket.getInetAddress() + "关闭连接\n目前在线:"  
  90.                     + mClientList.size();  
  91.             socket.close();  
  92.             this.sendMessage(message);  
  93.         }  
  94.   
  95.         /** 
  96.          * 将接收的消息转发给每一个客户端 
  97.          *  
  98.          * @param msg 
  99.          */  
  100.   
  101.         public void sendMessage(String msg) {  
  102.             System.out.println(msg);// 先在控制台输出  
  103.             int count = mClientList.size();  
  104.             // 遍历客户端集合  
  105.             for (int i = 0; i < count; i++) {  
  106.                 Socket mSocket = mClientList.get(i);  
  107.                 PrintWriter out = null;  
  108.                 try {  
  109.                     out = new PrintWriter(new BufferedWriter(  
  110.                             new OutputStreamWriter(mSocket.getOutputStream())),  
  111.                             true);// 创建输出流对象  
  112.                     out.println(msg);// 转发  
  113.                 } catch (IOException e) {  
  114.                     e.printStackTrace();  
  115.                 }  
  116.             }  
  117.         }  
  118.     }  
  119.   
  120. }  

二、Android客户端

思路:

设置权限。

首先开辟线程,在线程中连接服务器,并获取输入流和输出流,并用一个死循环接收来自服务器的消息,输入流收到消息进行处理,用handler通知给UI线程更新文本框。

编辑框填好消息,直接点击发送。用获得的输出流发送消息。

代码:

[java] view plain copy
  1. /** 
  2.  * Android Tcp即时通讯客户端 
  3.  */  
  4. public class MainActivity extends Activity implements Runnable{  
  5.     private TextView tv_msg = null;  
  6.     private EditText ed_msg = null;  
  7.     private Button btn_send = null;  
  8.     private static final String HOST = "192.168.0.100";//服务器地址  
  9.     private static final int PORT = 8888;//连接端口号  
  10.     private Socket socket = null;  
  11.     private BufferedReader in = null;  
  12.     private PrintWriter out = null;  
  13.   
  14.     //接收线程发送过来信息,并用TextView追加显示  
  15.     public Handler mHandler = new Handler() {  
  16.         public void handleMessage(Message msg) {  
  17.             super.handleMessage(msg);  
  18.             tv_msg.append((CharSequence) msg.obj);  
  19.         }  
  20.     };  
  21.   
  22.     @Override  
  23.     public void onCreate(Bundle savedInstanceState) {  
  24.         super.onCreate(savedInstanceState);  
  25.         setContentView(R.layout.activity_main);  
  26.   
  27.         tv_msg = (TextView) findViewById(R.id.txt_1);  
  28.         ed_msg = (EditText) findViewById(R.id.et_talk);  
  29.         btn_send = (Button) findViewById(R.id.btn_send);  
  30.   
  31.         btn_send.setOnClickListener(new Button.OnClickListener() {  
  32.   
  33.             @Override  
  34.             public void onClick(View v) {  
  35.                 String msg = ed_msg.getText().toString();  
  36.                 if (socket.isConnected()) {//如果服务器连接  
  37.                     if (!socket.isOutputShutdown()) {//如果输出流没有断开  
  38.                         out.println(msg);//点击按钮发送消息  
  39.                         ed_msg.setText("");//清空编辑框  
  40.                     }  
  41.                 }  
  42.             }  
  43.         });  
  44.         //启动线程,连接服务器,并用死循环守候,接收服务器发送过来的数据  
  45.         new Thread(this).start();  
  46.     }  
  47.   
  48.     /** 
  49.      * 连接服务器 
  50.      */  
  51.     private void connection() {  
  52.         try {  
  53.             socket = new Socket(HOST, PORT);//连接服务器  
  54.             in = new BufferedReader(new InputStreamReader(socket  
  55.                     .getInputStream()));//接收消息的流对象  
  56.             out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(  
  57.                     socket.getOutputStream())), true);//发送消息的流对象  
  58.         } catch (IOException ex) {  
  59.             ex.printStackTrace();  
  60.             ShowDialog("连接服务器失败:" + ex.getMessage());  
  61.         }  
  62.     }  
  63.   
  64.     /** 
  65.      * 如果连接出现异常,弹出AlertDialog! 
  66.      */  
  67.     public void ShowDialog(String msg) {  
  68.         new AlertDialog.Builder(this).setTitle("通知").setMessage(msg)  
  69.                 .setPositiveButton("ok"new DialogInterface.OnClickListener() {  
  70.   
  71.                     @Override  
  72.                     public void onClick(DialogInterface dialog, int which) {  
  73.   
  74.                     }  
  75.                 }).show();  
  76.     }  
  77.   
  78.     /** 
  79.      * 读取服务器发来的信息,并通过Handler发给UI线程 
  80.      */  
  81.     public void run() {  
  82.         connection();// 连接到服务器  
  83.         try {  
  84.             while (true) {//死循环守护,监控服务器发来的消息  
  85.                 if (!socket.isClosed()) {//如果服务器没有关闭  
  86.                     if (socket.isConnected()) {//连接正常  
  87.                         if (!socket.isInputShutdown()) {//如果输入流没有断开  
  88.                             String getLine;  
  89.                             if ((getLine = in.readLine()) != null) {//读取接收的信息  
  90.                                 getLine += "\n";  
  91.                                 Message message=new Message();  
  92.                                 message.obj=getLine;  
  93.                                 mHandler.sendMessage(message);//通知UI更新  
  94.                             } else {  
  95.   
  96.                             }  
  97.                         }  
  98.                     }  
  99.                 }  
  100.             }  
  101.         } catch (Exception e) {  
  102.             e.printStackTrace();  
  103.         }  
  104.     }  
  105.   
  106. }  


运行效果:




如果要扩展优化成一个有模有样的即时通讯工具。考虑发发送的消息用json进行格式化,包含用户昵称和图片地址等等,服务器收到后解析,在添加上时间等进行重新包装。客户端收到消息,同样进行解析,装载到美化好的listview当中。

原创粉丝点击