在Java中编写简单的局域网聊天室,核心依赖Socket网络编程实现客户端与服务端的通信,同时需要通过多线程处理多个客户端的并发连接和消息交互,避免单个客户端的阻塞影响整体服务。

核心实现思路
整个聊天室的架构分为服务端和客户端两部分:
- 服务端负责监听指定端口,接收客户端的连接请求,同时维护所有在线客户端的输出流,用于转发消息
- 每个客户端连接成功后,服务端会启动一个独立的线程处理该客户端的消息读取和转发逻辑
- 客户端需要单独启动线程读取服务端发来的消息,主线程负责读取用户输入并发送到服务端
服务端实现代码
服务端需要持续监听端口,每接收到一个客户端连接就创建一个新的处理线程,同时维护一个客户端输出流的集合用于消息广播。
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class ChatServer {
// 存储所有在线客户端的输出流
private static List<PrintWriter> clientWriters = new ArrayList<>();
public static void main(String[] args) {
int port = 8888;
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("聊天室服务端已启动,监听端口:" + port);
while (true) {
// 阻塞等待客户端连接
Socket clientSocket = serverSocket.accept();
System.out.println("新客户端连接成功:" + clientSocket.getInetAddress().getHostAddress());
// 启动线程处理该客户端
new Thread(new ClientHandler(clientSocket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 向所有在线客户端转发消息
public static void broadcastMessage(String message, PrintWriter excludeWriter) {
for (PrintWriter writer : clientWriters) {
if (writer != excludeWriter) {
writer.println(message);
}
}
}
static class ClientHandler implements Runnable {
private Socket socket;
private PrintWriter writer;
public ClientHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try (Scanner scanner = new Scanner(socket.getInputStream());
PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
writer = out;
// 将当前客户端的输出流加入集合
clientWriters.add(writer);
String clientAddress = socket.getInetAddress().getHostAddress();
// 广播新用户加入的消息
broadcastMessage("用户[" + clientAddress + "]加入聊天室", writer);
// 循环读取客户端发送的消息
while (scanner.hasNextLine()) {
String message = scanner.nextLine();
// 广播客户端发送的消息
broadcastMessage("用户[" + clientAddress + "]:" + message, writer);
}
} catch (IOException e) {
System.out.println("客户端连接异常断开");
} finally {
// 移除断开连接的客户端输出流
clientWriters.remove(writer);
String clientAddress = socket.getInetAddress().getHostAddress();
broadcastMessage("用户[" + clientAddress + "]离开聊天室", null);
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
客户端实现代码
客户端需要实现两个功能:向服务端发送用户输入的消息,同时接收服务端转发的其他客户端的消息,因此需要启动一个额外的线程处理消息接收。
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class ChatClient {
public static void main(String[] args) {
String serverIp = "127.0.0.1";
int port = 8888;
try (Socket socket = new Socket(serverIp, port);
Scanner inputScanner = new Scanner(System.in);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
System.out.println("成功连接到聊天室服务端");
// 启动线程读取服务端发来的消息
new Thread(new ServerMessageReader(socket)).start();
// 主线程读取用户输入并发送到服务端
while (inputScanner.hasNextLine()) {
String message = inputScanner.nextLine();
out.println(message);
}
} catch (IOException e) {
System.out.println("连接聊天室服务端失败");
e.printStackTrace();
}
}
static class ServerMessageReader implements Runnable {
private Socket socket;
public ServerMessageReader(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try (Scanner scanner = new Scanner(socket.getInputStream())) {
while (scanner.hasNextLine()) {
String message = scanner.nextLine();
System.out.println(message);
}
} catch (IOException e) {
System.out.println("与服务端的连接已断开");
}
}
}
}
运行测试步骤
按照以下步骤可以测试聊天室的基本功能:
- 先启动ChatServer类的main方法,服务端开始监听8888端口
- 多次运行ChatClient类的main方法,启动多个客户端,可以填写服务端的局域网IP(如果是本机测试用127.0.0.1即可)
- 任意一个客户端输入消息后,所有其他客户端都会收到转发的内容
- 关闭某个客户端的进程,其他客户端会收到该用户离开的提示
注意事项
- 如果要在局域网内其他设备连接,需要把服务端的防火墙对应端口开放,同时客户端填写服务端的实际局域网IP
- 上述代码是基础实现,没有做异常处理和消息格式规范,实际使用时可以扩展添加用户名设置、私聊、消息时间戳等功能
- 多线程处理时要注意共享集合clientWriters的线程安全问题,上述示例是简单实现,高并发场景下需要添加同步控制
Java_Socket多线程局域网聊天室网络编程修改时间:2026-06-21 11:03:32