【问题标题】:TCP Socket Hangs while receiving in Java在 Java 中接收时 TCP 套接字挂起
【发布时间】:2010-10-29 13:30:32
【问题描述】:

我在我的 Java 应用程序中使用 TCP 套接字。我正在尝试使用 readInt() 方法从某些设备接收字节数据。

如果我从设备获得 4 个字节,则此方法可以正常工作。但如果我得到少于 4 个字节,或者什么都没有,那么 readInt() 挂起。它被阻止并且不会返回。如果没有数据可以接收,它应该抛出 EOFException 异常,但它正在挂起。

代码:

DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
DataInputStream   din = new DataInputStream(socket.getInputStream());

int res = din.readInt();

【问题讨论】:

    标签: java sockets


    【解决方案1】:

    在套接字关闭之前不会抛出 EOFException

    当您尝试读取的数据多于可用数据时,此方法应该阻塞。它仅在套接字关闭时返回 EOFException,因为这是实际的 EOF 条件。如果套接字保持打开状态,它将阻塞,直到它有足够的数据来填充请求。

    这是套接字工作方式的基本性质的一部分。如果 Java 有任何不同的行为,就必须错误地实现套接字行为。

    在组合您的套接字协议时,您应该考虑这一点。为什么要等待接收 int 并且只发送 int 的一部分?这不应该发生。如果你想发送不同类型的数据,你应该首先包含一些头字节,告诉接收者接下来会收到什么样的数据,以便它知道如何处理它以及如何处理它。

    【讨论】:

    • 没错,阻塞是一种自然行为。
    【解决方案2】:

    该异常可能仅在连接的另一端关闭套接字时引发。否则,接收方没有迹象表明不会有更多数据,因此它会等待(当您调用readInt 时,您确实告诉它至少要获取四个字节)。您必须自己读取字节并将其解析为应用程序块。

    【讨论】:

      【解决方案3】:

      您使用的类是执行阻塞 I/O 的java.io 包的一部分。正确的解决方案是切换到使用java.nio 中定义的非阻塞 I/O 类。请注意,编写非阻塞 I/O 应用程序并非易事。但是,这是避免 I/O 线程可能无限期阻塞的唯一解决方案。

      请注意,作为一个 hacky 解决方案,您可以使用专用的阻塞 I/O 线程,该线程只需读取字节并将字节添加到由另一个线程轮询的 BlockingQueue。消费者线程可以用相当长的超时值在BlockingQueue 上调用poll(long, TimeUnit),如果调用返回null,这可能意味着没有更多数据可用。请注意,这是一个相当丑陋的解决方案,因为这意味着您的 I/O“生产者”线程此时将保持阻塞状态。

      【讨论】:

      • 不,正确的解决方案是在设备不发送时不要尝试读取 4 字节整数。
      • @EJP:这会让你的应用程序受制于设备;如果设备存在错误或者它只是脱机/无法访问(留下一个悬空的 TCP 套接字),您的应用程序线程将无限期地阻塞。因此,使用阻塞 I/O 并不是一个优雅的解决方案。
      • 这完全不真实。只需设置读取超时。然后应用程序将只阻塞超时的长度,然后抛出一个 SocketTimeoutException。这种情况并没有使 java.nio 成为“正确的解决方案”。这是众多之一。
      【解决方案4】:

      只有当您错误地实现了应用程序协议时,才会出现这种情况。为什么你期望一个 4 字节的整数,而应用程序只发送 1-3 个字节?它真的发送二进制 int 吗?还是应该读取和解析 ASCII 字符串?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-09-10
        • 2019-10-14
        • 1970-01-01
        • 2021-01-14
        • 2012-08-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多