在NIO模型中,服务器端和客户端的代码实现都遵循非阻塞I/O操作的原则,以下是一个简单的NIO服务器端和客户端的代码示例。
1. NIO服务器端代码
1.1 创建选择器和通道
我们创建一个Selector
和一个监听特定端口的ServerSocketChannel
。
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 NIOServer { public static void main(String[] args) throws IOException { // 创建选择器 Selector selector = Selector.open(); // 创建ServerSocketChannel ServerSocketChannel serverSocket = ServerSocketChannel.open(); InetSocketAddress address = new InetSocketAddress("localhost", 9090); serverSocket.bind(address); serverSocket.configureBlocking(false); SelectionKey selectorKey = serverSocket.register(selector, SelectionKey.OP_ACCEPT); System.out.println("Server started on port 9090"); // 主循环,处理事件 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()) { // 接受新连接 handleAccept(serverSocket, selector); } else if (key.isReadable()) { // 读取数据 handleRead(key); } keyIterator.remove(); } } } }
1.2 处理新连接和读取数据
我们需要实现handleAccept
和handleRead
方法来处理新的连接请求和读取数据。
static void handleAccept(ServerSocketChannel serverSocket, Selector selector) throws IOException { SocketChannel client = serverSocket.accept(); client.configureBlocking(false); client.register(selector, SelectionKey.OP_READ); System.out.println("New connection accepted: " + client.getRemoteAddress()); } static void handleRead(SelectionKey key) throws IOException { SocketChannel client = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); int bytesRead = client.read(buffer); if (bytesRead == 1) { client.close(); } else { buffer.flip(); // 在这里可以对读取到的数据进行处理 System.out.println("Data read from client: " + new String(buffer.array(), StandardCharsets.UTF_8)); } }
2. NIO客户端代码
2.1 创建选择器和通道
对于客户端,我们也需要创建一个Selector
和一个SocketChannel
。
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 NIOClient { public static void main(String[] args) throws IOException { // 创建选择器和通道 Selector selector = Selector.open(); SocketChannel socketChannel = SocketChannel.open(); socketChannel.configureBlocking(false); socketChannel.connect(new InetSocketAddress("localhost", 9090)); socketChannel.register(selector, SelectionKey.OP_CONNECT); // 主循环,处理事件 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.isConnectable()) { // 完成连接过程 connect(socketChannel); } else if (key.isWritable()) { // 写入数据 write(socketChannel); } keyIterator.remove(); } } } }
2.2 完成连接和写入数据
实现connect
和write
方法来完成连接过程和发送数据。
static void connect(SocketChannel socketChannel) throws IOException { if (socketChannel.isConnectionPending()) { while (!socketChannel.finishConnect()) { // wait, or do something else... } System.out.println("Connected to server"); } socketChannel.configureBlocking(false); socketChannel.register(Selector.open(), SelectionKey.OP_WRITE); } static void write(SocketChannel socketChannel) throws IOException { String message = "Hello from client!"; ByteBuffer buffer = ByteBuffer.allocate(1024); buffer.put(message.getBytes(StandardCharsets.UTF_8)); buffer.flip(); while (buffer.hasRemaining()) { socketChannel.write(buffer); } buffer.clear(); System.out.println("Message sent to server: " + message); }
相关问题与解答
Q1: NIO与传统的BIO相比有哪些优势?
A1: NIO(Nonblocking I/O)相较于传统的BIO(Blocking I/O)有多个优势:它能够处理更多的并发连接,因为NIO使用非阻塞模式;通过一个线程管理多个连接,减少了线程切换的开销;提高了应用程序的可扩展性和性能。
Q2: 在NIO模型中,如果一个连接既不是读也不是写,那么它的状态是什么?
A2: 在NIO模型中,如果一个连接既不是读也不是写,那么它可能是处于建立连接(OP_CONNECT)或者正在关闭状态(OP_CLOSE),这些状态可以通过检查SelectionKey
的interestSet()
方法来确定。
原创文章,作者:未希,如若转载,请注明出处:https://www.kdun.com/ask/925629.html
本网站发布或转载的文章及图片均来自网络,其原创性以及文中表达的观点和判断不代表本网站。如有问题,请联系客服处理。
发表回复