java nio op_write,在nio OP_READ和OP_WRITE操作之间进行通信

I'm trying to implement java.nio Selector based http server (for fun). On key.isReadable() I'm reading data like this:

ByteBuffer buf = ByteBuffer.allocate(4096);

SocketChannel client = (SocketChannel) key.channel();

//Gathering whole client request

((ByteBufferQueue) key.attachment()).enqueue(buf);

key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);

Please, look at gathering client's request. Is it a common practice to collect ByteBuffers in some kind of queues during OP_READ operations? Is there any other (more optimal) way to communicate between OP_READ and OP_WRITE operations?

解决方案

Allocate a ByteBuffer per accepted channel, and save it as the key attachment, or in a session object that is used as the key attachment, that might contain other things as well.

When OP_READ fires, you should then read. Don't futz around queuing things.

NB OP_WRITE is almost always ready, except when the socket send buffer is full. It is therefore not correct to register it as an interestOp except when the socket buffer is full, which you can detect by write() returning zero. At all other times you should just write when you have something to write. If write() returns zero, then register OP_WRITE (and not OP_READ), and when you get it, retry the write: if it completes, deregister OP_WRITE and register OP_READ. If you have OP_WRITE registered all the time, the selector will never wait, it will just spin.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 NIO 通信代码示例,其中使用了 Java 的 SocketChannel 和 Selector 类: ```java 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.SocketChannel; import java.util.Iterator; public class NIOClient { private static final int BUFFER_SIZE = 1024; private static final String HOST = "localhost"; private static final int PORT = 8080; public static void main(String[] args) { try { SocketChannel socketChannel = SocketChannel.open(); socketChannel.configureBlocking(false); Selector selector = Selector.open(); socketChannel.register(selector, SelectionKey.OP_CONNECT); socketChannel.connect(new InetSocketAddress(HOST, PORT)); while (true) { if (selector.select() <= 0) { continue; } Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); if (key.isConnectable()) { SocketChannel channel = (SocketChannel) key.channel(); if (channel.isConnectionPending()) { channel.finishConnect(); } channel.configureBlocking(false); channel.register(selector, SelectionKey.OP_WRITE); System.out.println("Connected to server: " + HOST + ":" + PORT); } else if (key.isWritable()) { SocketChannel channel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); buffer.put("Hello, Server!".getBytes()); buffer.flip(); channel.write(buffer); channel.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { SocketChannel channel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); channel.read(buffer); String message = new String(buffer.array()).trim(); System.out.println("Received message from server: " + message); channel.close(); selector.close(); System.exit(0); } } } } catch (IOException e) { e.printStackTrace(); } } } ``` 该示例使用了 JavaNIO 技术,通过 SocketChannel 和 Selector 类实现客户端与服务器之间通信。在客户端中,首先创建一个 SocketChannel 对象,并将其配置为非阻塞模式。然后创建一个 Selector 对象并将 SocketChannel 注册到 Selector 上,设置监听事件为 OP_CONNECT。接着调用 connect() 方法来连接服务器。 在 while 循环中,首先使用 select() 方法阻塞等待事件发生。如果没有事件发生,则继续循环等待。如果有事件发生,则获取事件的 SelectionKey 并根据其对应的操作类型进行处理。如果是 OP_CONNECT 事件,则完成连接操作并将 SocketChannel 注册为 OP_WRITE 事件。如果是 OP_WRITE 事件,则向服务器发送数据,并将 SocketChannel 注册为 OP_READ 事件。如果是 OP_READ 事件,则从服务器读取数据,并关闭连接和 Selector。 注意,在这个示例中,我们只是发送了一条简单的字符串消息给服务器,并从服务器接收了一条回复消息。在实际应用中,您可能需要更复杂的协议和数据格式来进行通信

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值