Java NIO

java NIO有2种模式,一种是非阻塞,一种是阻塞式的,阻塞式的和传统的BIO类似,不过可靠性不如BIO,故一般不用

 

以下关注非阻塞的方式,

NIO是非阻塞同步IO,工作在一个线程中,由selector去轮询channel,是否有请求连接就绪/读取就绪,有就进行连接/读取到buffer

当然从另一方面也可以说是阻塞的,因为selector一直在执行select方法,尝试获取通道的事件,未获取到的话就阻塞一定的时间后返回,并继续select

// server端代码

public static void main(String[] args) throws  Exception{
//创建ServerSocketChannel,-->> ServerSocket
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
InetSocketAddress inetSocketAddress = new InetSocketAddress(5555);
serverSocketChannel.socket().bind(inetSocketAddress);
serverSocketChannel.configureBlocking(false); //设置成非阻塞

//开启selector,并注册accept事件
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

while(true) {
selector.select(2000); //监听所有通道
//遍历selectionKeys
Set<SelectionKey> selectionKeys = selector.selectedKeys();
String s = selectionKeys.toString();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
if(key.isAcceptable()) { //处理连接事件
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false); //设置为非阻塞
System.out.println("client:" + socketChannel.getLocalAddress() + " is connect");
socketChannel.register(selector, SelectionKey.OP_READ); //注册客户端读取事件到selector
} else if (key.isReadable()) { //处理读取事件
ByteBuffer byteBuffer = ByteBuffer.allocate(32);
SocketChannel channel = (SocketChannel) key.channel();
int read = channel.read(byteBuffer);

if (read == -1) {
key.cancel();
System.out.println("client closed");
continue;
}
byteBuffer.flip();
String str = StandardCharsets.UTF_8.decode(byteBuffer).toString();
System.out.println("received client:" + channel.getLocalAddress() + read+" str " + str);
}
iterator.remove(); //事件处理完毕,要记得清除
}
}

}


// client端代码

private static void sendByNIO()throws Exception{
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 5555);

if(!socketChannel.connect(inetSocketAddress)) {
while (!socketChannel.finishConnect()) {
System.out.println("客户端正在连接中,请耐心等待");
}
}
ByteBuffer byteBuffer = ByteBuffer.wrap("test msg.qwertyuikl1234567890123456789123123456789!!!!".getBytes(StandardCharsets.UTF_8));
socketChannel.write(byteBuffer);
Thread.sleep(1000*60);
socketChannel.close();
}


以上是单线程的情况,一个reactor来处理所有的事件,连接,读写,也可以复杂的使用多个reactor,主reactor负责连接,读写交给副reactor,副reactor的读写的操作还可以交给线程池中的专门线程来处理

 

 

 

 

图来自于https://blog.csdn.net/wang2963973852/article/details/74418643

 



posted @ 2024-03-21 15:53  坏男银  阅读(11)  评论(0编辑  收藏  举报