【问题标题】:Using Blocking NIO in Java在 Java 中使用阻塞 NIO
【发布时间】:2016-05-10 14:21:43
【问题描述】:

我只是想知道是否可以使用 SocketChannel 类(带有 ByteBuffer)来模拟 Java 中常规 Socket 类的阻塞特性。我做了两个Test项目,一个模拟Client,另一个模拟Server:

客户代码:

    public static void main(String[] args) throws IOException {

    SocketChannel socket = SocketChannel.open(new InetSocketAddress("127.0.0.1", 6789));

    //Simulate this:
    //DataOutputStream dos = new DataOutputStream(socket.socket().getOutputStream());
    //dos.writeInt(4);
    //dos.writeInt(6);

    ByteBuffer buffer = ByteBuffer.allocate(4);
    buffer.putInt(4);
    buffer.flip();
    socket.write(buffer);
    buffer.clear();
    buffer.putInt(6);
    buffer.flip();
    socket.write(buffer);
}

服务器代码:

    public static void main(String[] args) throws IOException, InterruptedException {
    ServerSocketChannel ssc = ServerSocketChannel.open();
    ssc.socket().bind(new InetSocketAddress(6789));
    SocketChannel socketCh = ssc.accept();
    socketCh.configureBlocking(true);
    // Simulate this
    // DataInputStream dis = new DataInputStream(socketCh.socket().getInputStream());
    // System.out.println(dis.readInt());
    // System.out.println(dis.readInt());

    // This is something to avoid. This is not the same as what is up above
    // If the 2nd line prints -1, the 3rd prints 4
    // If the 2nd line prints 4, the 3rd prints 6
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    socketCh.read(buffer);
    buffer.rewind();
    System.out.println("First number: " + buffer.getInt());
    buffer.clear();
    System.out.println("Change: " + socketCh.read(buffer));
    buffer.rewind();
    System.out.println("Second Number: " + buffer.getInt());
}

正如我在 cmets 中所说,运行服务器然后运行客户端(按此顺序)的结果是不可预测的,因为有时第二个数字可能保持为 4 或变为 6,更改为 -1 或 4(字节整数)。

至于服务器端,我知道我可以让它等待,以便第二个 socketCh.read(buffer) 返回一个非 -1 的值,这意味着(我认为)SocketChannel 中没有写入任何内容。

但是,在客户端,我没有任何想法。

我知道我可以改用 DataOutputStream 和 DataInputStream 并以老式方式执行此操作,但为了方便起见,我想知道如何使用 SocketChannels 执行此操作。此外,你也不会出错。

尽管我手动将服务器配置为阻塞,但我认为它是默认配置,因此可以丢弃它。

提前感谢您! PS:希望我可以避免在这样一个简单的任务中使用 Selector 类...

编辑:我知道 Selector 类只能用于非阻塞模式。

【问题讨论】:

    标签: java nio socketchannel


    【解决方案1】:

    您正在丢弃可能已读取的额外数据,并假设每次读取都准确地交付与每次写入相对应的数据(例如,第一个仅交付 int)。 TCP 中没有任何东西可以保证这一点。

    rewind()改成flip();将clear() 更改为compact();添加一些检查read()的返回值;它应该按预期工作。

    您不能在阻塞模式下使用Selector

    【讨论】:

    • 好的,谢谢!是的,我知道您不能在阻塞模式下使用 Selector,但是我希望避免必须将 SocketChannel 配置为非阻塞并且必须为这个简单的任务执行所有这些操作。
    • 在我详细阅读了 compact() 所做的事情后,这让我感觉更有意义了。这就是我浏览一本书所得到的结果:\。谢谢大佬,非常感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-31
    • 2012-01-01
    • 2023-03-06
    • 1970-01-01
    • 2020-12-30
    • 1970-01-01
    相关资源
    最近更新 更多