Android使用多线程进行网络聊天室通信

Android使用多线程进行网络聊天室通信,第1张

概述TCP/IP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket,从而在通信的两端之间形成网络虚拟链路。一旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信了。Java对基于TCP协议的网络通信提

TCP/IP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket,从而在通信的两端之间形成网络虚拟链路。一旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信了。Java对基于TCP协议的网络通信提供了良好的封装,Java使用Socket对象来代表两端通信接口,并通过Socket产生IO流来进行网络通信。

下面的程序Demo是实现一个简单的C/S聊天室的应用,每个客户端该包含两条线程:一条负责生成主界面,响应用户动作,并将用户输入的数据写入Socket对应的输出流中;另一条负责读取Socket对应的输入流中的数据(从服务器发送过来的数据),并负责将这些数据在程序界面上显示出来。
客户端程序是一个AndroID应用,因此需要创建一个AndroID项目,这个AndroID应用的界面中包含两个文本框:一个用于接收用户的输入;另一个用于显示聊天信息。界面中还有一个按钮,当用户单击该按钮时,程序向服务器发送聊天信息。
layout/activity_main.xml界面布局代码如下:

@H_403_8@<?xml version="1.0" enCoding="utf-8"?><linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" androID:orIEntation="vertical"> <linearLayout androID:layout_wIDth="match_parent" androID:layout_height="wrap_content" androID:orIEntation="horizontal"> <!-- 定义一个文本框,它用于接收用户的输入 --> <EditText androID:ID="@+ID/input" androID:layout_wIDth="280dp" androID:layout_height="wrap_content" /> <button androID:ID="@+ID/send" androID:layout_wIDth="match_parent" androID:layout_height="wrap_content" androID:paddingleft="8dp" androID:text="发送" /> </linearLayout> <!-- 定义一个文本框,它用于显示来自服务器的信息 --> <TextVIEw androID:ID="@+ID/show" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" androID:background="#ffff" androID:gravity="top" androID:textcolor="#f000" androID:textSize="18sp" /></linearLayout>

客户端的Activity负责生成程序界面,并为程序的按钮单击事件绑定事件监听器,当用户单击按钮时向服务器发送信息。
MainActivity.java逻辑代码如下:

package com.fukaimei.multithreadclIEnt;import androID.os.Bundle;import androID.os.Handler;import androID.os.Message;import androID.support.v7.app.AppCompatActivity;import androID.vIEw.VIEw;import androID.vIEw.VIEw.OnClickListener;import androID.Widget.button;import androID.Widget.EditText;import androID.Widget.TextVIEw;public class MainActivity extends AppCompatActivity { // 定义界面上的两个文本框 EditText input; TextVIEw show; // 定义界面上的一个按钮 button send; Handler handler; // 定义与服务器通信的子线程 ClIEntThread clIEntThread; @OverrIDe public voID onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentVIEw(R.layout.activity_main);  input = (EditText) findVIEwByID(R.ID.input);  send = (button) findVIEwByID(R.ID.send);  show = (TextVIEw) findVIEwByID(R.ID.show);  handler = new Handler() // ②  {   @OverrIDe   public voID handleMessage(Message msg) {    // 如果消息来自于子线程    if (msg.what == 0x123) {     // 将读取的内容追加显示在文本框中     show.append("\n" + msg.obj.toString());    }   }  };  clIEntThread = new ClIEntThread(handler);  // 客户端启动ClIEntThread线程创建网络连接、读取来自服务器的数据  new Thread(clIEntThread).start(); // ①  send.setonClickListener(new OnClickListener() {   @OverrIDe   public voID onClick(VIEw v) {    try {     // 当用户按下发送按钮后,将用户输入的数据封装成Message     // 然后发送给子线程的Handler     Message msg = new Message();     msg.what = 0x234;     msg.obj = input.getText().toString();     clIEntThread.revHandler.sendMessage(msg);     // 清空input文本框     input.setText("");    } catch (Exception e) {     e.printstacktrace();    }   }  }); }}

当用户单击该程序界面中的“发送”按钮后,程序将会把input输入框中的内容发送给clIEntThread的revHandler对象,clIEntThread负责将用户输入的内容发送给服务器。

ClIEntThread子线程负责建立与远程服务器的连接,并负责与远程服务器通信,读到数据之后便通过Handler对象发送一条消息;当ClIEntThread子线程收到UI线程发送过来的消息后,还负责将用户输入的内容发送给远程服务器。

ClIEntThread.java逻辑代码如下:

package com.fukaimei.multithreadclIEnt;import androID.os.Handler;import androID.os.Looper;import androID.os.Message;import androID.util.Log;import java.io.BufferedReader;import java.io.IOException;import java.io.inputStreamReader;import java.io.OutputStream;import java.net.socket;import java.net.socketTimeoutException;public class ClIEntThread implements Runnable { private static final String TAG = "ClIEntThread"; private Socket s; // 定义向UI线程发送消息的Handler对象 private Handler handler; // 定义接收UI线程的消息的Handler对象 public Handler revHandler; // 该线程所处理的Socket所对应的输入流 BufferedReader br = null; OutputStream os = null; public ClIEntThread(Handler handler) {  this.handler = handler; } public voID run() {  try {   s = new Socket("172.xx.xx.xxx",30000);   br = new BufferedReader(new inputStreamReader(     s.getinputStream()));   os = s.getoutputStream();   // 启动一条子线程来读取服务器响应的数据   new Thread() {    @OverrIDe    public voID run() {     String content = null;     // 不断读取Socket输入流中的内容     try {      while ((content = br.readline()) != null) {       // 每当读到来自服务器的数据之后,发送消息通知程序       // 界面显示该数据       Message msg = new Message();       msg.what = 0x123;       msg.obj = content;       handler.sendMessage(msg);      }     } catch (IOException e) {      e.printstacktrace();     }    }   }.start();   // 为当前线程初始化Looper   Looper.prepare();   // 创建revHandler对象   revHandler = new Handler() {    @OverrIDe    public voID handleMessage(Message msg) {     // 接收到UI线程中用户输入的数据     if (msg.what == 0x234) {      // 将用户在文本框内输入的内容写入网络      try {       os.write((msg.obj.toString() + "\r\n")         .getBytes("utf-8"));      } catch (Exception e) {       e.printstacktrace();      }     }    }   };   // 启动Looper   Looper.loop();  } catch (SocketTimeoutException e1) {   Log.d(TAG,"网络连接超时!");  } catch (Exception e) {   e.printstacktrace();  } }}

上面线程的功能也非常简单,它只是不断地获取Socket输入流中的内容,当读到Socket输入流中的内容后,便通过Handler对象发送一条消息,消息负责携带读到的数据。除此之外,该子线程还负责读取UI线程发送的消息,接收到消息之后,该子线程负责中携带的数据发送给远程服务器。

服务器端应该包含多条线程,每个Socket对应一条线程,该线程负责读取Socket对应输入流,并将读到的数据向每个Socket输出流发送一遍,因此需要在服务器端使用List来保存所有的Socket。
下面是服务器端的代码。程序为服务器提供了两个类:一个是创建ServerSocket监听的主类;另一个是负责处理每个Socket通信的线程类。

/MultiThreadServer/src/MyServer.java逻辑代码如下:

import java.io.IOException;import java.net.ServerSocket;import java.net.socket;import java.util.ArrayList;public class MyServer { // 定义保存所有Socket的ArrayList public static ArrayList<Socket> socketList = new ArrayList<Socket>(); public static voID main(String[] args) throws IOException {  ServerSocket ss = new ServerSocket(30000);  while (true) {   // 此行代码会阻塞,将一直等待别人的连接   Socket s = ss.accept();   socketList.add(s);   // 每当客户端连接后启动一条ServerThread线程为该客户端服务   new Thread(new ServerThread(s)).start();  } }}

上面的程序是服务器端只负责接收客户端Socket的连接请求,每当客户端Socket连接到该ServerSocket之后,程序将对应Socket加入socketList集合中保存,并为该Socket启动一条线程,该程序负责处理该Socket所有的通信任务。服务器端线程类的代码如下。

/MultiThreadServer/src/ServerThread.java逻辑代码如下:

import java.io.BufferedReader;import java.io.IOException;import java.io.inputStreamReader;import java.io.OutputStream;import java.net.socket;import java.util.Iterator;// 负责处理每条线程通信的线程类public class ServerThread implements Runnable { // 定义当前线程所处理的Socket Socket s = null; // 该线程所处理的Socket所对应的输入流 BufferedReader br = null; public ServerThread(Socket s) throws IOException {  this.s = s;  // 初始化该Socket对应的输入流  br = new BufferedReader(new inputStreamReader(s.getinputStream(),"utf-8")); } @OverrIDe public voID run() {  String content = null;  // 采用循环不断从Socket中读取客户端发送过来的数据  while ((content = readFromClIEnt()) != null) {   // 遍历socketList中的每个Socket   // 将读取的内容向每个Socket发送一次   for (Iterator<Socket> it = MyServer.socketList.iterator(); it.hasNext();) {    Socket s = it.next();    try {     OutputStream os = s.getoutputStream();     os.write((content + "\n").getBytes("utf-8"));    } catch (Exception e) {     e.printstacktrace();     // 删除该Socket     it.remove();     System.out.println(MyServer.socketList);    }   }  } } // 定义读取客户端数据的方法 private String readFromClIEnt() {  try {   return br.readline();  } catch (IOException e) { // 如果捕获到异常,表明该Socket对应的客户端已经关闭   e.printstacktrace();   // 删除该Socket   MyServer.socketList.remove(s);  }  return null; }}

上面的服务器端线程类不断读取客户端数据,程序使用readFromClIEnt()方法来读取客户端数据,如果在读数据过程中捕获到IOException异常,则表明该Socket对应的客户端Socket出现问题,程序就将该Socket从socketList中删除。
当服务器线程读到客户端数据之后,程序遍历socketList集合,并将该数据向socketList集合中的每个Socket发送一次――该服务器线程将把从Socket中读到的数据向socketList中的每个Socket转发一次。

先运行上面程序的MyServer类,该类运行后只是作为服务器,看不到任何输出。接着可以运行AndroID客户端――相当于启动聊天界面登录该服务器,接下来在任何一个AndroID客户端输入一些内容后单击“发送”按钮,将可以看到所有客户端(包含自己)都会收到刚刚输入的内容,这样就简单实现了一个C/S结构的聊天室的功能。
注意:由于该程序需要访问互联网,因此还需要在清单文件AndroIDManifest.xml文件中授权访问互联网的权限:

<!-- 授权访问互联网--> <uses-permission androID:name="androID.permission.INTERNET" />

Demo程序运行效果界面截图如下:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的Android使用多线程进行网络聊天室通信全部内容,希望文章能够帮你解决Android使用多线程进行网络聊天室通信所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1144127.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存