一、目标
这个项目是一个基于 TCP 协议的简单多人聊天系统,包含一个服务器和多个客户端。服务器接受多个客户端的连接,每个客户端发送的消息都可以转发给其他所有在线的客户端,实现了一个基本的多人实时聊天功能。项目使用 Java 编程语言编写,利用 ServerSocket
和 Socket
创建管道来实现客户端与服务器之间的通信。
二、各模块代码分析与解读
服务端总体代码:
服务端实现:
1. 创建一个 ServerSocket 来监听端口 9999。
2. 每当有客户端连接时,接受连接并将该客户端的 Socket 存储在在线列表中。
3. 每个连接的客户端创建一个新的线程(ServerThread1)来处理客户端的请求。
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class TcpServerDemo2 {
// 注册一个在线列表储存所有的Socket
public static List<Socket> onLineSockets = new ArrayList<>();
public static void main(String[] args) throws Exception {
try {
// 注册端口
ServerSocket serverSocket = new ServerSocket(9999);
while (true) {
// 监听客户端的连接请求,得到服务端socket
Socket socket = serverSocket.accept();
// 将新连接的客户端Socket加入在线列表
onLineSockets.add(socket);
System.out.println(socket.getInetAddress().getHostAddress() + " online");
// 为每个客户端创建一个新的线程来处理它的请求
ServerThread1 st1 = new ServerThread1(socket);
st1.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
服务端线程类:
1. 每个 ServerThread1 线程负责处理一个客户端的通信。
2. 线程启动后,通过输入流读取客户端的消息。
3. 服务器接收到消息后,通过 sendMsgtoAll() 方法将消息转发给所有其他在线客户端。
4. 当客户端断开连接时,捕获异常并输出断开信息。
import java.io.*;
import java.net.Socket;
public class ServerThread1 extends Thread {
Socket socket;
public ServerThread1(Socket socket) throws IOException {
this.socket = socket;
}
@Override
public void run() {
try {
// 从服务端中获取一个字节输入流。
InputStream is = socket.getInputStream();
// 把字节输入流包装成数据输入流
DataInputStream dis = new DataInputStream(is);
while (true) {
String Msg = dis.readUTF();
System.out.println(currentThread().getName() +
" Server Accepted : " + Msg + " "
+ "from : " + socket.getRemoteSocketAddress()
);
// 将收到的消息转发给其他所有在线客户端
sendMsgtoAll(Msg);
}
} catch (Exception e) {
// 处理异常情况,如客户端断开连接
System.out.println(socket.getRemoteSocketAddress() + "out");
}
}
private void sendMsgtoAll(String msg) throws IOException {
for (Socket socket : TcpServerDemo2.onLineSockets) {
// 不给自己的客户端发
if(socket == this.socket){
continue;
}else {
// 向其他客户端发送消息
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(msg);
dos.flush();
}
}
}
}
客户端总体代码:
客户端实现:
1. 创建一个 Socket 连接到服务器的 9999 端口。
2. 启动一个读取线程(ClientReadThread1)用于接收来自服务器的消息。
3. 主线程通过数据输出流发送用户输入的消息给服务器。
4. 用户可以输入 "exit" 来关闭连接并退出。
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class TcpClientDemo1 {
public static void main(String[] args) throws Exception {
// 创建一个Socket通信管道与服务端建立可靠连接
Socket socket = new Socket("127.0.0.1", 9999);
new ClientReadThread1(socket).start();
// 从socket通信管道中得到一个字节输出流。
OutputStream os = socket.getOutputStream();
// 把字节输出流包装成一个数据输出流
DataOutputStream dos = new DataOutputStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("Please Input :");
String s = sc.nextLine();
if(s.equalsIgnoreCase("exit")){
socket.close();
break;
}
dos.writeUTF(s);
}
}
}
客户端线程类:
1. 客户端启动 ClientReadThread1 线程来处理来自服务器的消息。
2. 线程通过输入流不断读取服务器转发的消息。
3. 读取到的消息会打印到客户端控制台上。
4. 当服务器断开连接时,捕获异常并输出断开信息。
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
public class ClientReadThread1 extends Thread {
Socket socket;
public ClientReadThread1(Socket socket) throws IOException {
this.socket = socket;
}
@Override
public void run() {
try {
// 从服务端中获取一个字节输入流。
InputStream is = socket.getInputStream();
// 把字节输入流包装成数据输入流
DataInputStream dis = new DataInputStream(is);
while (true) {
String Msg = dis.readUTF();
// 读取来自服务器的消息并打印在客户端显示
System.out.println("received: " + Msg);
}
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress() + "out");
}
}
}
三、总结
该项目是一个基于 TCP 协议的多人聊天系统。服务器通过 ServerSocket
监听客户端的连接,每个客户端连接后,服务器为其创建一个独立的线程来处理通信。服务器维护一个在线客户端的列表,当某个客户端发送消息时,服务器会将该消息转发给所有其他在线客户端。
客户端通过 Socket
连接服务器,并在一个独立的线程中不断读取来自服务器的转发消息。项目实现了基本的多人聊天功能,展示了 TCP 通信和多线程的应用,记录一个入门学习案例