如何测试非阻塞通道的SocketChannel.read()是否已完成



我正在使用一个函数从非阻塞SocketChannel(来自accept((的套接字(和阻塞SocketChannel(客户端(读取字节。我正在实现一个使用选择器来处理多个客户端的服务器,并且我正在使用环回地址来仅使用我的笔记本电脑。我写了这个

while((r = socketChannel.read(ackBuf)) != -1) {
System.out.println(name3d+" r: "+r);
}

我预计当到达通道中内容的末尾时,read((会返回-1,但不是成功的结果。read((,在非阻塞配置中,如果目前没有准备好读取,也会返回0,但很快就会读取(如果我理解得很好(,所以如果我将代码更改为

while((r = socketChannel.read(ackBuf)) > 0) {
System.out.println(name3d+" r: "+r);
}

如果稍后有东西准备好,我也不会什么都不读。如何区分我得到0是因为未准备好还是因为它已结束?在下面的片段中,我可以在睡眠后第二次测试读数,但我确信这不是实现我想要的目标的可靠方法。

int times = 0;
while((r = socketChannel.read(ackBuf)) != -1 && times<2) {
if (r == 0)
try {
Thread.sleep(500);
times++;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(name3d+" r: "+r);
}

"如果我得到0是因为没有准备好还是因为它已经结束?"你指的是消息还是整个通信?

对于消息,您应该使用通信协议(如json或http(进行通信,我认为您应该得到一个SocketException。。。如果你使用阻塞,而另一端的人关闭了连接。。。(我在SO上给很多人写过关于SocketException是你的朋友的信(

---编辑---

查看Channel的文档,如果/当channcel关闭时,您似乎应该得到某种IOException(SocketException是IOException的子类(

非阻塞SocketChannel的使用有点不同。

  1. 您首先等待选择键告诉您有数据,然后
  2. 然后从通道中读取数据

请参阅此代码草案:

Selector selector = Selector.open();
SocketChannel sc = SocketChannel.open();
sc.configureBlocking(false);
sc.connect(addr);
sc.register(selector, SelectionKey.OP_READ);
while (true) {
// select() can block!
if (selector.select() == 0) {
continue;
}
Iterator iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
if (key.isReadable()) {
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer bb = ByteBuffer.allocate(1024);
sc.read(bb);
System.out.println("Message received!");
}
}

最新更新