处理可写事件
什么情况下需要注册可写事件?
- 在服务端一次性无法把数据发送完的情况下,需要注册可写事件
- 服务端一次性是否能够把数据全部发送完成取决于服务端的缓冲区大小,该缓冲区不受程序控制
注册可写事件的步骤
-
判断ByteBuffer是否仍有剩余,如果有剩余注册可写事件
ByteBuffer bf = "hello client,welcome"; SocketChannel sc = (SocketChannel) selectionKey.channel(); sc.write(bf); if(bf.hasRemaining){ selectionKey.interestOps(SelectionKey.OP_READ + SelectionKey.OP_WRITE); selectionKey.attachment(bf); }
-
监听可写事件,判断数据是否写完,数据写完需要
if (key.isWritable()){ // 监听可写事件 SocketChannel channel = (SocketChannel) key.channel(); ByteBuffer byteBuffer = (ByteBuffer) key.attachment(); channel.write(byteBuffer); if (!byteBuffer.hasRemaining()) { // 判断数据是否写完 // 数据写完,解除对buffer的引用 key.attach(null); // 数据写完,不再关注可写事件 key.interestOps(key.interestOps() - SelectionKey.OP_WRITE); } }
代码示例
-
客户端文章来源:https://www.toymoban.com/news/detail-673294.html
package com.ysf; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; public class Client { public static void main(String[] args) throws IOException { SocketChannel sc = SocketChannel.open(); sc.connect(new InetSocketAddress("127.0.0.1",11027)); sc.write(Charset.defaultCharset().encode("123456\n223456\nhello server\n")); while (true){ ByteBuffer allocate = ByteBuffer.allocate(16); sc.read(allocate); allocate.flip(); System.out.println(Charset.defaultCharset().decode(allocate)); } } }
-
服务端文章来源地址https://www.toymoban.com/news/detail-673294.html
package com.ysf; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class WriterSelectorServer { public static void handleContent(ByteBuffer byteBuffer){ byteBuffer.flip(); for (int i = 0;i < byteBuffer.limit();i++){ if (byteBuffer.get(i) == '\n'){ int length = i + 1 - byteBuffer.position(); ByteBuffer allocate = ByteBuffer.allocate(length); for (int j = 0;j<length;j++){ allocate.put(byteBuffer.get()); } allocate.flip(); System.out.println(Charset.defaultCharset().decode(allocate)); } } byteBuffer.compact(); } public static void main(String[] args) throws IOException { Selector selector = Selector.open(); ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.configureBlocking(false); ssc.bind(new InetSocketAddress(11027)); SelectionKey sscKey = ssc.register(selector, 0, null); sscKey.interestOps(SelectionKey.OP_ACCEPT); while (true){ selector.select(); Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()){ SelectionKey key = iterator.next(); iterator.remove(); if (key.isAcceptable()){ ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel(); SocketChannel sc = serverSocketChannel.accept(); sc.configureBlocking(false); ByteBuffer welcome = Charset.defaultCharset().encode("welcome"); sc.write(welcome); Map<String,ByteBuffer> attach = new HashMap<>(); ByteBuffer readBuffer = ByteBuffer.allocate(16); attach.put("read",readBuffer); SelectionKey scKey = sc.register(selector, 0, attach); if (welcome.hasRemaining()){ attach.put("write",welcome); scKey.interestOps(SelectionKey.OP_READ + SelectionKey.OP_WRITE); }else { scKey.interestOps(SelectionKey.OP_READ); } }else if (key.isReadable()){ SocketChannel channel = (SocketChannel) key.channel(); Map<String, ByteBuffer> attachment = ((Map<String,ByteBuffer>) key.attachment()); ByteBuffer readBuffer = attachment.get("read"); int read; try { read = channel.read(readBuffer); } catch (IOException e) { e.printStackTrace(); key.cancel(); continue; } if (read == -1){ key.cancel(); }else { handleContent(readBuffer); if (readBuffer.position() == readBuffer.limit()){ ByteBuffer newAttachment = ByteBuffer.allocate(readBuffer.capacity() * 2); readBuffer.flip(); newAttachment.put(readBuffer); attachment.put("read",newAttachment); } } }else if (key.isWritable()){ SocketChannel channel = (SocketChannel) key.channel(); Map<String, ByteBuffer> attachment = (Map<String, ByteBuffer>) key.attachment(); ByteBuffer byteBuffer = attachment.get("write"); channel.write(byteBuffer); if (!byteBuffer.hasRemaining()) { attachment.remove("write"); key.interestOps(key.interestOps() - SelectionKey.OP_WRITE); } } } } } }
到了这里,关于netty(二):NIO——处理可写事件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!