博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java NIO中Write事件和Connect事件
阅读量:7065 次
发布时间:2019-06-28

本文共 3943 字,大约阅读时间需要 13 分钟。

NIO Server端多路复用开发的一般步骤是:
//打开选择器Selector selector = Selector.open();//打开通到ServerSocketChannel socketChannel = ServerSocketChannel.open();//配置非阻塞模型socketChannel.configureBlocking(false);//绑定端口socketChannel.bind(new InetSocketAddress(8080));//注册事件,OP_ACCEPT只适用于ServerSocketChannel socketChannel.register(selector, SelectionKey.OP_ACCEPT);while (true) {    selector.select();    Set
selectionKeys = selector.selectedKeys(); Iterator
iter = selectionKeys.iterator(); while(iter.hasNext()) { SelectionKey key = iter.next(); if(key.isAcceptable()) { SocketChannel channel = ((ServerSocketChannel)key.channel()).accept(); channel.configureBlocking(false); channel.register(selector,SelectionKey.OP_READ); } if(key.isWritable()) { } if(key.isReadable()) { SocketChannel channel = (SocketChannel) key.channel(); ByteBuffer readBuffer = ByteBuffer.allocate(512); channel.read(readBuffer); readBuffer.flip(); //handler Buffer //一般是响应客户端的数据 //直接是write写不就完事了嘛,为啥需要write事件? //channel.write(...) } iter.remove(); }}

刚开始对NIO的写操作理解的不深,不知道为什么要注册写事件,何时注册写事件,为什么写完之后要取消注册写事件。

如果有channelSelector上注册了SelectionKey.OP_WRITE事件,在调用selector.select();时,系统会检查内核写缓冲区是否可写(什么时候是不可写的呢,比如缓冲区已满,channel调用了shutdownOutPut等等),如果可写,selector.select();立即返回,随后进入key.isWritable()分支。

当然你在channel上可以直接调用write(...),也可以将数据发送出去,但这样不够灵活,而且可能浪费CPU

看一个场景,服务端需要发送一个200MBuffer,看看使用OP_WRITE事件和不使用的区别。

//不使用事件,缺点是,程序运行到这会等到200M文件发送完成后才继续往下执行,不符合异步事件模型//的编程思想,如果缓冲区一直处于不可写状态,那么该过程一直在这里死循环,浪费了CPU资源。ByteBuffer buffer = .... //200M的Bufferwhile(buffer.hasRemaining()) {    //该方法只会写入小于socket's output buffer空闲区域的任何字节数    //并返回写入的字节数,可能是0字节。    channel.write(buffer);}//使用事件的方式,谁好谁坏,一看便知if(key.isReadable()) {    ByteBuffer buffer = .... //200M的Buffer    //注册写事件    key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);    //绑定Buffer    key.attach(buffer);}//isWritable分支if(key.isWritable()) {    ByteBuffer buffer = (ByteBuffer) key.attachment();    SocketChannel channel = (SocketChannel) key.channel();    if (buffer.hasRemaining()) {        channel.write(buffer)    } else {        //发送完了就取消写事件,否则下次还会进入该分支        key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);    }}
客户端开发的一般步骤:
//打开选择器Selector selector = Selector.open();//打开通道SocketChannel socketChannel = SocketChannel.open();//配置非阻塞模型socketChannel.configureBlocking(false);//连接远程主机socketChannel.connect(new InetSocketAddress("127.0.0.1",8080));//注册事件socketChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ);//循环处理while (true) {    selector.select();    Set
keys = selector.selectedKeys(); Iterator
iter = keys.iterator(); while(iter.hasNext()) { SelectionKey key = iter.next(); if(key.isConnectable()) { //连接建立或者连接建立不成功 SocketChannel channel = (SocketChannel) key.channel(); //完成连接的建立 if(channel.finishConnect()) { } } if(key.isReadable()) { SocketChannel channel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(500 * 1024 * 1024); buffer.clear(); channel.read(buffer); //buffer Handler } iter.remove(); }}

起初对OP_CONNECT事件还有finishConnect不理解,OP_CONNECT事件何时触发,特别是为什么要在key.isConnectable()分支里调用finishConnect方法后才能进行读写操作。

首先,在non-blocking模式下调用socketChannel.connect(new InetSocketAddress("127.0.0.1",8080));连接远程主机,如果连接能立即建立就像本地连接一样,该方法会立即返回true,否则该方法会立即返回false,然后系统底层进行三次握手建立连接。连接有两种结果,一种是成功连接,第二种是异常,但是connect方法已经返回,无法通过该方法的返回值或者是异常来通知用户程序建立连接的情况,所以由OP_CONNECT事件和finishConnect方法来通知用户程序。不管系统底层三次连接是否成功,selector都会被唤醒继而触发OP_CONNECT事件,如果握手成功,并且该连接未被其他线程关闭,finishConnect会返回true,然后就可以顺利的进行channle读写。如果网络故障,或者远程主机故障,握手不成功,用户程序可以通过finishConnect方法获得底层的异常通知,进而处理异常。

转载地址:http://afill.baihongyu.com/

你可能感兴趣的文章
25 JavaScript的幻灯片用于在Web布局的精彩案例
查看>>
用C语言写的迅雷看看XV文件提取器及C语言源代码
查看>>
ccpuid:CPUID信息模块 V1.01版,支持GCC(兼容32位或64位的Windows/Linux)
查看>>
用dom4j操作XML文档(收集)
查看>>
WinForm实例源代码下载
查看>>
hdu 1829 A Bug's Life(并查集)
查看>>
每日英语:Chinese Writer Wins Literature Nobel
查看>>
java中三种主流数据库数据库(sqlserver,db2,oracle)的jdbc连接总结
查看>>
Oracle Apps AutoConfig
查看>>
[leetcode]Flatten Binary Tree to Linked List
查看>>
css颜色代码大全:(网页设计师和平面设计师常用)
查看>>
boost 1.52在windows下的配置
查看>>
素材锦囊——50个高质量的 PSD 素材免费下载《上篇》
查看>>
【转】oc中消息传递机制-附:对performSelector方法的扩充
查看>>
oracle的nvl和sql server的isnull
查看>>
[转]虚拟机下Ubuntu共享主机文件(Ubuntu、VMware、共享)
查看>>
高血压 治疗 偏方
查看>>
HtmlAttribute HTML属性处理类
查看>>
[书目20130316]jQuery UI开发指南
查看>>
Sql Server系列:开发存储过程
查看>>