一、引言
在当今的移动互联网时代,实时通讯已经成为应用开发中的一个重要组成部分,Android平台上实现一个高效的网络聊天室,不仅能够提升用户体验,还能为开发者提供丰富的实践经验,本文将详细介绍如何在Android平台上使用多线程技术实现一个基于TCP/IP协议的网络聊天室。
二、背景知识
TCP/IP协议简介
TCP/IP(Transmission Control Protocol/Internet Protocol)是一种面向连接的、可靠的传输层协议,它在通信双方之间建立一个虚拟链路,保证数据包的顺序传输和正确接收,Java提供了良好的API支持,通过Socket类来实现TCP通信。
Java中的Socket编程
Java对Socket编程提供了全面的支持,主要涉及以下两个核心类:
Socket:用于表示客户端的通信端点。
ServerSocket:用于表示服务器端的通信端点。
Android中的多线程
Android中的多线程编程主要用于处理耗时操作,防止阻塞主线程(UI线程),从而提高应用的响应速度和用户体验,常用的多线程方式包括:
AsyncTask:适用于短期的后台操作。
Thread:适用于需要长时间运行的后台任务。
HandlerThread:适用于需要在后台线程中执行并通信的任务。
三、系统架构设计
客户端/服务器(C/S)架构
网络聊天室通常采用C/S架构,即一个服务器和多个客户端,服务器负责管理所有客户端的连接、消息转发等,而客户端则负责用户界面的展示和与服务器的通信。
客户端功能模块
用户界面模块:负责展示聊天界面,包括输入框、消息显示框和发送按钮。
网络通信模块:负责与服务器建立连接、发送和接收消息。
消息处理模块:负责处理接收到的消息并更新用户界面。
四、客户端实现
1. 布局文件(activity_main.xml)
<?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>
2. 客户端逻辑实现(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(" " + msg.obj.toString()); } } }; clientThread = new ClientThread(handler); new Thread(clientThread).start(); send.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { try { String content = input.getText().toString(); Message msg = new Message(); msg.what = 0x234; msg.obj = content; clientThread.revHandler.sendMessage(msg); input.setText(""); } catch (Exception e) { e.printStackTrace(); } } }); } }
3. 客户端通信线程(ClientThread.java)
package com.fukaimei.multithreadclient; import android.os.Handler; import android.os.Message; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class ClientThread implements Runnable { private Handler revHandler; private String ip = "127.0.0.1"; // 服务器IP地址 private int port = 12345; // 服务器端口号 private PrintWriter printWriter; private BufferedReader bufferedReader; private boolean isRunning = true; private Socket socket; public ClientThread(Handler revHandler) { this.revHandler = revHandler; } @Override public void run() { try { socket = new Socket(ip, port); printWriter = new PrintWriter(socket.getOutputStream(), true); bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); while (isRunning) { String content = bufferedReader.readLine(); if (content != null) { Message msg = new Message(); msg.what = 0x123; msg.obj = content; revHandler.sendMessage(msg); } } } catch (Exception e) { e.printStackTrace(); } finally { try { bufferedReader.close(); printWriter.close(); socket.close(); } catch (Exception e) { e.printStackTrace(); } } } }
五、服务器端实现
1. 服务器端逻辑(SocketServer.java)
package com.example.socketserver; import java.io.*; import java.net.*; import java.util.concurrent.*; import java.util.*; public class SocketServer { private static final int PORT = 12345; private static ExecutorService executorService = Executors.newFixedThreadPool(5); private static List<Socket> clients = Collections.synchronizedList(new ArrayList<>()); private static ServerSocket serverSocket; private static PrintWriter printWriter; private static BufferedReader bufferedReader; private static boolean isRunning = true; public static void main(String[] args) throws IOException { serverSocket = new ServerSocket(PORT); System.out.println("服务端就绪..."); while (isRunning) { Socket client = serverSocket.accept(); // 等待客户端连接 clients.add(client); // 将新的客户端添加到列表中 executorService.execute(new Service(client)); // 为每个客户端创建一个新线程处理请求 } } }
2. 服务器端会话处理(Service.java)
package com.example.socketserver; import java.io.*; import java.net.*; public class Service implements Runnable { private Socket client; private PrintWriter printWriter; private BufferedReader bufferedReader; private String userName; private boolean isRunning = true; private List<Socket> clients; // 引用客户端列表以便广播消息 private ServerSocket serverSocket; // 引用服务器套接字以便关闭连接时通知所有客户端 private PrintWriter serverPrintWriter; // 引用服务器的PrintWriter以便广播消息给所有客户端除了当前客户端外其他客户端也要接收到此消息所以这里要用到一个集合来存储所有的客户端套接字然后遍历这个集合向每个客户端发送消息这样就实现了聊天室内消息共享的功能了!注意要排除掉自己哦~否则就成了自言自语啦哈哈~~不过这里为了简单起见暂时没有实现用户名功能如果需要的话可以自行添加进去哈~比如可以在客户端连接成功后首先提示用户输入用户名然后再将其加入到客户端列表中这样就可以根据用户名来进行消息的收发了当然这只是一种实现方式具体还可以根据实际需求进行调整比如可以采用数据库等方式来保存用户信息等等这些都看你自己的选择了总之方法有很多关键是要找到适合自己的那一种才行啊!好了废话不多说直接上代码吧!希望对你有所帮助哦~嘻嘻~~加油加油再加油!!!你一定可以成为最棒的程序员哒!!!相信自己一定行滴!!!奥利给!!!耶!!!胜利属于我们!!!哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*//* /* * @brief 构造函数 * * @param client * @param clients * @param serverSocket * @param serverPrintWriter * @return void * @endbrief */public Service(Socket client, List<Socket> clients, ServerSocket serverSocket, PrintWriter serverPrintWriter) {this.client = client;this.clients = clients;this.serverSocket = serverSocket;this.serverPrintWriter = serverPrintWriter;init();}/** * @brief 初始化函数 * * @return void * @endbrief */private void init() {try {printWriter = new PrintWriter(client.getOutputStream(), true);bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));userName = getUserName();} catch (IOException e) {e.printStackTrace();}}/** * @brief 获取用户名函数 * * @return String * @endbrief */private String getUserName() throws IOException {printWriter.println("请输入用户名:");printWriter.flush();return bufferedReader.readLine();}/** * @brief 读取客户端消息函数 * * @return void * @endbrief */private void readMessage() {while (isRunning) {try {String message = bufferedReader.readLine();if (message != null && !message.equals("exit")) {System.out.println("收到消息:" + message);for (Socket client : clients) {if (!client.isClosed() && !client.equals(this.client)) {serverPrintWriter.println("[" + userName + "]: " + message);}}}else if (message.equals("exit")) {isRunning = false;break;}catch (IOException e) {e.printStackTrace();}}}}/** * @brief 关闭连接函数 * * @return void * @endbrief */private void closeConnection() {try {if (printWriter != null) {printWriter.close();}if (bufferedReader != null) {bufferedReader.close();}if (client != null) {client.close();}} catch (IOException e) {e.printStackTrace();}}}}```
原创文章,作者:未希,如若转载,请注明出处:https://www.kdun.com/ask/1260390.html
本网站发布或转载的文章及图片均来自网络,其原创性以及文中表达的观点和判断不代表本网站。如有问题,请联系客服处理。
发表回复