基于Java Socket的简易聊天室实现步骤
通过Java Socket和网络编程技术,可以构建支持多用户连接的聊天系统。本文将详细解析如何利用BIO(同步阻塞I/O)模型,结合多线程处理并发连接,实现包含用户名认证、群组广播及私聊功能的完整聊天室应用。
项目架构设计
聊天室采用C/S(客户端/服务器)架构,通信过程分为两个阶段:首先是身份认证,其次是即时通讯。为了确保系统的健壮性,建议先备份重要项目文件,防止代码冲突导致的数据丢失。
第1步:定义登录认证类 UserLogin
目的:建立预置的用户白名单,用于校验客户端提交的用户名是否合法。
核心逻辑:使用 HashSet 存储允许登录的用户标识(如 "111" 至 "555"),通过 contains() 方法快速判断。
import java.util.HashSet;
import java.util.Set;
public class UserLogin {
// 初始化合法用户集合
public static Set initUser() {
Set set = new HashSet<>();
set.add("111");
set.add("222");
set.add("333");
set.add("444");
set.add("555");
return set;
}
// 验证登录状态
public static boolean login(String username) {
Set set = initUser();
return set.contains(username);
}
}
第2步:创建登录服务器 LoginServer
入口:TCP端口 6666。
动作:监听来自客户端的连接请求,读取用户名并调用认证方法。若认证成功,向客户端返回字符串 true,否则返回 false。
参数说明:需确保输入流与输出流的正确关闭及刷新,避免数据阻塞。
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class LoginServer {
public static void main(String[] args) {
int port = 6666;
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("登录服务器已经启动");
while (true) {
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String username = bufferedReader.readLine();
OutputStream outputStream = socket.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
if (UserLogin.login(username)) {
System.out.println(username + "登录成功");
printStream.println("true");
} else {
System.out.println(username + "登录失败");
printStream.println("false");
}
printStream.flush();
// 注意:此处仅完成认证,未关闭socket以便后续连接到聊天服务器
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
第3步:创建聊天服务器 ChatServer
入口:TCP端口 9999。
动作:接收已认证用户的连接,将 <username, Socket> 存入全局 Map 中。为每个连接启动独立的线程 ChatThread 以处理该用户的消息收发。
关键状态:实时维护在线用户列表,作为消息转发的基础。
import com.socket.socketChatroom.bio.thread.ChatThread;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
public class ChatServer {
// 保存当前所有在线用户的Socket映射
public static Map socketMap = new HashMap<>();
public static void main(String[] args) {
int port = 9999;
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("聊天服务器已经启动");
while (true) {
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String username = bufferedReader.readLine();
System.out.println(username + "连接到聊天服务器");
socketMap.put(username, socket);
System.out.println(socketMap);
// 为新连接创建独立线程进行处理
new ChatThread(username, socket).start();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
第4步:实现客户端 Client 主程序
流程:先连接 LoginServer (port 6666) 进行验证;若返回 true,则建立与 ChatServer (port 9999) 的新连接。
并发处理:一旦建立聊天连接,立即启动发送线程 WriteThread 和接收线程 ReadThread,实现收发消息互不阻塞。
import com.socket.socketChatroom.bio.thread.ReadThread;
import com.socket.socketChatroom.bio.thread.WriteThread;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class Client {
public static void main(String[] args) {
String ip = "127.0.0.1";
int port = 6666; // 登录端口
try {
Socket client = new Socket(ip, port);
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名");
String username = scanner.nextLine();
// 发送用户名到登录服务器
OutputStream outputStream = client.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
printStream.println(username);
printStream.flush();
// 接收认证结果
InputStream inputStream = client.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String state = bufferedReader.readLine();
if (Boolean.parseBoolean(state)) {
chat(username); // 登录成功,进入聊天流程
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void chat(String username) {
try {
String ip = "127.0.0.1";
int port = 9999; // 聊天端口
Socket socket = new Socket(ip, port);
// 向聊天服务器发送用户名
OutputStream outputStream = socket.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
printStream.println(username);
printStream.flush();
// 启动收发线程
new ReadThread(socket).start();
new WriteThread(socket).start();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
第5步:服务端消息分发线程 ChatThread
逻辑:循环读取客户端发来的消息。根据消息格式判断是单聊还是群聊:
- 单聊:消息格式为
目标用户-内容,查找目标Socket并转发。 - 群聊:遍历所有在线Socket(除自身外),广播消息。
import com.socket.socketChatroom.bio.server.ChatServer;
import java.io.*;
import java.net.Socket;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class ChatThread extends Thread {
private final String username;
private final Socket socket;
public ChatThread(String username, Socket socket) {
this.username = username;
this.socket = socket;
}
@Override
public void run() {
while (true) {
try {
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String message = bufferedReader.readLine();
System.out.println(username + "说: " + message);
Map socketMap = ChatServer.socketMap;
Set usernameSet = new HashSet<>();
for (Map.Entry map : socketMap.entrySet()) {
usernameSet.add(map.getKey());
}
// 解析单聊/群聊
String[] values = message.split("-");
if (values.length == 2 && usernameSet.contains(values[0])) { // 单聊
OutputStream out = socketMap.get(values[0]).getOutputStream();
PrintStream ps = new PrintStream(out);
ps.println(username + "说: " + values[1]);
ps.flush();
} else { // 群聊
for (String targetUser : usernameSet) {
if (socket != socketMap.get(targetUser)) {
OutputStream out = socketMap.get(targetUser).getOutputStream();
PrintStream ps = new PrintStream(out);
ps.println(this.username + "说: " + message);
ps.flush();
}
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
第6步:客户端发送线程 WriteThread
作用:独立于主线程运行,负责监听用户键盘输入并通过Socket发送给服务器。
注意:输入格式需符合服务器解析规则。
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
public class WriteThread extends Thread {
private final Socket socket;
public WriteThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
while (true) {
try {
OutputStream outputStream = socket.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
Scanner scanner = new Scanner(System.in);
System.out.println("请输入聊天内容: ");
String message = scanner.nextLine();
printStream.println(message);
printStream.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
第7步:客户端接收线程 ReadThread
作用:持续从服务器拉取消息并在控制台打印,确保用户可以随时看到他人发送的消息。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
public class ReadThread extends Thread {
private final Socket socket;
public ReadThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
while (true) {
try {
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String message = bufferedReader.readLine();
System.out.println(message);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
项目结构展示
完整的工程目录应清晰分离服务器端、客户端及辅助线程类,方便管理。项目结构如图:
运行与测试流程
在IDEA中运行本示例时,需注意以下几点以确保服务正常开启:
- 首先依次启动
LoginServer和ChatServer。 - 由于需要模拟多个用户同时在线,需配置IDEA允许多个实例并行运行。
- 具体操作路径:进入
Run/Debug Configurations,勾选Allow parallel run。
IDEA多实例配置界面如下:
8.1 登录环节测试
启动客户端后,控制台会提示输入用户名。输入预设的合法用户(如 "111")即可成功进入聊天系统。若输入非法用户则会被拒绝。登录交互过程见下图:
8.2 群聊测试
当多个用户同时在线时,直接发送消息内容(不带前缀),服务器将识别为群聊指令,并将消息分发给除发送者外的所有在线客户端。
8.3 单聊测试
在输入框中输入 目标用户名-消息内容 的格式(例如 222-hello),系统将识别为私聊,仅目标用户能收到该条消息。
以上就是基于Java Socket实现聊天室功能的详细内容,更多关于Java网络编程实战的资料请关注本站其它相关文章!免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









