-
源码分析:
- ServerSocketChannel是一个可以监听新进来的TCP连接的通道,就像标准IO中的ServerSocket一样。
- 通过ServerSocketChannel.accept()方法监听新进来的连接。当accept()方法返回的时候,它返回一个包含新进来的连接的SocketChannel。
- ServerSocketChannel可以设置成非阻塞模式:serverSocketChannel.configureBlocking(false); 在非阻塞模式下,accept()方法会立刻返回,如果还没有新进来的连接,返回的将是null。
-
服务端和客户端源码:
public class NioDiscardServer {
public static void startServer() throws IOException {
Selector selector = Selector.open();// 1、获取Selector选择器
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 2、获取通道
serverSocketChannel.configureBlocking(false); // 3.设置为非阻塞
serverSocketChannel.bind(new InetSocketAddress(9000));// 4、绑定连接
// 5、将通道注册到选择器上,并注册的IO事件为:“接收新连接”
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
// 6、轮询感兴趣的I/O就绪事件(选择键集合)
while (selector.select() > 0) {
// 7、获取选择键集合
Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
SelectionKey selectedKey = selectedKeys.next();// 8、获取单个的选择键,并处理
// 9、判断key是具体的什么事件,不同的事件类型,做不同的处理
if (selectedKey.isAcceptable()) {
// 10-1、若选择键的IO事件是“连接就绪”事件,就获取客户端连接,此时新的客户端请求连接,需要获取链接通道,并将通道绑定到选择器上。
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false); // 10-1、切换为非阻塞模式
socketChannel.register(selector, SelectionKey.OP_READ); // 10-1、将该通道注册到selector选择器上
} else if (selectedKey.isReadable()) {
// 10-2、若选择键的IO事件是“可读”事件,读取数据
SocketChannel socketChannel = (SocketChannel) selectedKey.channel();
// 10-2、读取数据
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
int length = 0;
while ((length = socketChannel.read(byteBuffer)) >0) {
byteBuffer.flip();
Logger.info(new String(byteBuffer.array(), 0, length));
byteBuffer.clear();
}
socketChannel.close();
}
// 15、移除选择键
selectedKeys.remove();
}
}
// 7、关闭连接
serverSocketChannel.close();
}
public static void main(String[] args) throws IOException {
startServer();
}
}
public class NioDiscardClient {
public static void startClient() throws IOException {
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(127.0.01,9000));// 1、获取通道(channel)
socketChannel.configureBlocking(false); // 2、切换成非阻塞模式
while (!socketChannel.finishConnect()) { //3.不断的自旋、等待连接完成,或者做一些其他的事情
}
ByteBuffer byteBuffer = ByteBuffer.allocate(1024); // 4、分配指定大小的缓冲区
byteBuffer.put("hello world".getBytes());
byteBuffer.flip();
socketChannel.write(byteBuffer);
socketChannel.shutdownOutput();
socketChannel.close();
}
public static void main(String[] args) throws IOException {
startClient();
}
}