设计与实现一个网络聊天的服务器程序,用于接收并转发多个客户端程序之前通信的消息和数据。要求使用多线程或异步I/O模型提升服务器程序性能。
时间: 2024-02-19 17:59:20 浏览: 29
下面是一个使用Java NIO异步I/O模型实现的网络聊天服务器程序的示例代码,可以接收并转发多个客户端程序之间通信的消息和数据:
```java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
public class ChatServer {
private static Selector selector;
private static ByteBuffer buffer = ByteBuffer.allocate(1024);
public static void main(String[] args) {
try {
// 创建Selector和ServerSocketChannel
selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress("localhost", 8888));
// 将ServerSocketChannel注册到Selector上,监听连接事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务器已启动,等待客户端连接...");
while (true) {
// 轮询已注册的Channel,等待IO事件发生
selector.select();
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (key.isAcceptable()) { // 处理连接事件
SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
System.out.println("客户端 " + channel.getRemoteAddress() + " 已连接!");
broadcastMessage("客户端 " + channel.getRemoteAddress() + " 已连接!");
} else if (key.isReadable()) { // 处理读事件
SocketChannel channel = (SocketChannel) key.channel();
buffer.clear();
int count = channel.read(buffer);
if (count > 0) {
buffer.flip();
String message = new String(buffer.array(), 0, count);
System.out.println("客户端 " + channel.getRemoteAddress() + " 发来消息: " + message);
broadcastMessage("客户端 " + channel.getRemoteAddress() + " 发来消息: " + message);
} else if (count == -1) { // 客户端断开连接
channel.close();
System.out.println("客户端 " + channel.getRemoteAddress() + " 已断开连接!");
broadcastMessage("客户端 " + channel.getRemoteAddress() + " 已断开连接!");
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 广播消息给所有客户端
private static void broadcastMessage(String message) throws IOException {
for (SelectionKey key : selector.keys()) {
Channel channel = key.channel();
if (channel instanceof SocketChannel) {
SocketChannel socketChannel = (SocketChannel) channel;
socketChannel.write(ByteBuffer.wrap(message.getBytes()));
}
}
}
}
```
该示例代码使用Java NIO提供的Selector、ServerSocketChannel、SocketChannel等类实现异步I/O模型。在main()方法中,创建Selector和ServerSocketChannel,并将ServerSocketChannel注册到Selector上,监听连接事件。在轮询已注册的Channel时,处理连接事件和读事件,并将读到的消息广播给所有客户端。使用ByteBuffer缓存读到的数据,并在读到换行符或达到缓存大小时进行处理。广播消息时,遍历所有已注册的Channel,并将消息写入SocketChannel中发送给客户端。
使用异步I/O模型可以提高服务器程序的并发性能和响应速度,因为异步I/O模型不需要为每个客户端请求创建一个线程,而是使用一个线程来处理多个客户端请求。此外,在处理读事件时,可以使用Java NIO提供的非阻塞I/O方式,提高程序性能。