Java NIO 网络编程模型中的 Acceptor-Connector 模式是一种常用的模式,用于处理客户端连接请求和服务端响应请求。
在 Acceptor-Connector 模式中,服务端的 Acceptor 负责监听客户端的连接请求,并接受连接,同时启动一个新的线程池,把已连接的客户端传递给 Connector,由 Connector 负责处理客户端请求,包括读取数据、处理数据、写入数据等操作。
这种模式的优点在于,可以将 Acceptor 和 Connector 的职责分离,使得服务端的响应能力更强,同时能够处理多个客户端的请求,并发性能更高。
以下是一个基于 Acceptor-Connector 模式的示例代码,其中包含了 Channel、Buffer、Selector、ServerSocketChannel 和 SocketChannel 等的使用。代码实现了一个简单的 TCP 服务器,接收客户端发送的消息并回复相同的消息。
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
public class TcpServer {
private static final int BUFFER_SIZE = 1024;
private static final int PORT = 8888;
private Selector selector;
private ByteBuffer readBuffer = ByteBuffer.allocate(BUFFER_SIZE);
private ByteBuffer writeBuffer = ByteBuffer.allocate(BUFFER_SIZE);
public void start() throws IOException {
selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(PORT));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server started on port " + PORT);
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();
if (key.isAcceptable()) {
accept(key);
} else if (key.isReadable()) {
read(key);
} else if (key.isWritable()) {
write(key);
}
keyIterator.remove();
}
}
}
private void accept(SelectionKey key) throws IOException {
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
System.out.println("Accepted new connection from " + socketChannel.getRemoteAddress());
}
private void read(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
readBuffer.clear();
int numBytesRead = socketChannel.read(readBuffer);
if (numBytesRead == -1) {
System.out.println("Connection closed by " + socketChannel.getRemoteAddress());
socketChannel.close();
key.cancel();
return;
}
String request = new String(readBuffer.array(), 0, numBytesRead).trim();
System.out.println("Received request from " + socketChannel.getRemoteAddress() + ": " + request);
key.interestOps(SelectionKey.OP_WRITE);
}
private void write(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
String response = new String(readBuffer.array(), 0, readBuffer.position());
writeBuffer.clear();
writeBuffer.put(response.getBytes());
writeBuffer.flip();
socketChannel.write(writeBuffer);
key.interestOps(SelectionKey.OP_READ);
}
public static void main(String[] args) {
try {
new TcpServer().start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
在该代码中,首先通过 Selector.open() 创建一个 Selector 对象,然后通过 ServerSocketChannel.open() 创建一个 ServerSocketChannel 对象,绑定端口并注册到 Selector 上,以监听客户端连接请求。
在 while 循环中,调用 selector.select() 阻塞等待就绪的事件,一旦有事件就绪,就会从选择器的键集中获取到对应的键,并通过键来获取对应的通道,然后进行后续的操作,例如读取数据或写入数据等。