本文目录导读:

这是一个使用Java NIO构建的简易聊天室实现方案,我将为你提供完整的代码结构和核心实现逻辑。
整体架构
ChatRoom
├── ChatServer.java // 服务器端
├── ChatClient.java // 客户端
└── UserInputHandler.java // 用户输入处理
服务器端实现
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
public class ChatServer {
private static final int PORT = 8888;
private static final Charset CHARSET = Charset.forName("UTF-8");
public void start() throws IOException {
// 1. 创建Selector
Selector selector = Selector.open();
// 2. 创建ServerSocketChannel
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().bind(new InetSocketAddress(PORT));
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务器启动,监听端口:" + PORT);
// 3. 事件循环
while (true) {
int readyChannels = selector.select();
if (readyChannels == 0) continue;
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
keyIterator.remove();
if (!key.isValid()) continue;
// 处理新连接
if (key.isAcceptable()) {
acceptConnection(selector, key);
}
// 处理读事件
else if (key.isReadable()) {
readMessage(selector, key);
}
}
}
}
private void acceptConnection(Selector selector, SelectionKey key) throws IOException {
ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
SocketChannel clientChannel = serverChannel.accept();
clientChannel.configureBlocking(false);
clientChannel.register(selector, SelectionKey.OP_READ);
// 广播新用户加入消息
System.out.println("用户 [" + clientChannel.getRemoteAddress() + "] 加入聊天室");
broadcastMessage(selector, clientChannel,
"系统消息:新用户 [" + clientChannel.getRemoteAddress() + "] 加入聊天室");
}
private void readMessage(Selector selector, SelectionKey key) throws IOException {
SocketChannel clientChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
StringBuilder message = new StringBuilder();
try {
int bytesRead = clientChannel.read(buffer);
if (bytesRead == -1) {
// 客户端断开连接
System.out.println("用户 [" + clientChannel.getRemoteAddress() + "] 离开聊天室");
broadcastMessage(selector, clientChannel,
"系统消息:用户 [" + clientChannel.getRemoteAddress() + "] 离开聊天室");
key.cancel();
clientChannel.close();
return;
}
buffer.flip();
message.append(CHARSET.decode(buffer).toString().trim());
String msg = message.toString();
if (msg.length() > 0) {
System.out.println("收到消息:" + msg);
// 广播消息给所有其他客户端
broadcastMessage(selector, clientChannel,
"[" + clientChannel.getRemoteAddress() + "]: " + msg);
}
} catch (IOException e) {
// 异常处理:关闭连接
key.cancel();
clientChannel.close();
}
}
private void broadcastMessage(Selector selector, SocketChannel sender, String message)
throws IOException {
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes(CHARSET));
for (SelectionKey key : selector.keys()) {
Channel channel = key.channel();
if (channel instanceof SocketChannel && channel != sender) {
SocketChannel target = (SocketChannel) channel;
target.write(buffer);
buffer.rewind();
}
}
}
public static void main(String[] args) throws IOException {
new ChatServer().start();
}
}
客户端实现
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
public class ChatClient {
private static final String SERVER_HOST = "localhost";
private static final int SERVER_PORT = 8888;
private static final Charset CHARSET = Charset.forName("UTF-8");
public void start() throws IOException {
// 创建Selector
Selector selector = Selector.open();
// 创建SocketChannel并连接服务器
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress(SERVER_HOST, SERVER_PORT));
socketChannel.register(selector, SelectionKey.OP_CONNECT);
// 启动用户输入线程
new Thread(new UserInputHandler(socketChannel)).start();
// 事件循环
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
keyIterator.remove();
if (!key.isValid()) continue;
// 处理连接事件
if (key.isConnectable()) {
connectToServer(key);
}
// 处理读事件
else if (key.isReadable()) {
readFromServer(key);
}
}
}
}
private void connectToServer(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
if (channel.isConnectionPending()) {
channel.finishConnect();
}
channel.configureBlocking(false);
channel.register(key.selector(), SelectionKey.OP_READ);
System.out.println("已连接到聊天服务器");
}
private void readFromServer(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
StringBuilder message = new StringBuilder();
int bytesRead = channel.read(buffer);
if (bytesRead == -1) {
System.out.println("服务器连接断开");
key.cancel();
channel.close();
return;
}
buffer.flip();
message.append(CHARSET.decode(buffer).toString().trim());
if (message.length() > 0) {
System.out.println(message.toString());
}
}
public static void main(String[] args) throws IOException {
new ChatClient().start();
}
}
用户输入处理
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
public class UserInputHandler implements Runnable {
private SocketChannel socketChannel;
private static final Charset CHARSET = Charset.forName("UTF-8");
public UserInputHandler(SocketChannel socketChannel) {
this.socketChannel = socketChannel;
}
@Override
public void run() {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
String input;
while ((input = reader.readLine()) != null) {
if ("/quit".equalsIgnoreCase(input)) {
System.out.println("退出聊天室");
System.exit(0);
}
ByteBuffer buffer = ByteBuffer.wrap(input.getBytes(CHARSET));
socketChannel.write(buffer);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用方法
-
启动服务器:
javac ChatServer.java java ChatServer
-
启动多个客户端:
javac ChatClient.java UserInputHandler.java java ChatClient
关键特性说明
非阻塞I/O
- 所有操作都是非阻塞的,一个线程可以处理多个连接
- 使用Selector实现事件驱动
事件处理
OP_ACCEPT: 处理新客户端连接OP_READ: 读取客户端消息OP_CONNECT: 客户端连接服务器
消息广播
- 服务器收到消息后广播给所有其他客户端
- 使用ByteBuffer进行数据传输
用户交互
- 输入
/quit退出聊天室 - 消息格式:
[客户端地址]: 消息内容
扩展建议
- 添加用户名:连接时发送用户名
- 私聊功能:支持
@用户 消息格式 - 消息队列:使用消息队列处理并发消息
- 心跳检测:定期检测客户端连接状态
- 日志记录:记录聊天历史
这个简易聊天室实现了基本的NIO聊天功能,你可以根据需求进行扩展和优化。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播