【问题标题】:How can I test if a SocketChannel.read() for a non-blocking channel has finished?如何测试非阻塞通道的 SocketChannel.read() 是否已完成?
【发布时间】:2020-06-12 17:33:14
【问题描述】:

我正在使用一个函数从非阻塞 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 是因为没有准备好还是因为它结束了? 在下面的 sn-p 中,我可以在睡眠后第二次测试读取,但我确信这不是做我想做的事情的可靠方法。

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);
}

【问题讨论】:

    标签: java sockets nio nonblocking socketchannel


    【解决方案1】:

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

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

    --- 编辑---

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

    【讨论】:

    • 我说的是消息。我使用我自己的协议,在客户端设置与服务器的 TCP 通信后,客户端通过 socketchannel 发送一些字节,第一个字节用于标识特定请求,以便服务器了解客户端请求的请求类型。以类似的方式服务器向客户端发送字节
    【解决方案2】:

    Non-blocking 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!");
         }
    }
    

    【讨论】:

    • 所以如果选择了socketChannel的key,我永远不会得到0!这说明了一切。谢谢:)
    • 辩解,不一定。但是你有很大的机会得到超过 0 的大部分时间。 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多