2010-10-29 131 views
2

我在我的Java应用程序中使用TCP Socket。我试图用readInt()方法从某个设备接收字节数据。TCP Socket在Java中接收时挂起

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

代码:

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

int res = din.readInt(); 

回答

4

EOFException不抛出,直至插槽关闭。

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

这是套接字工作方式的基本性质的一部分。对于Java的行为有任何不同,它将不得不不正确地实现套接字行为。

把你的套接字协议放在一起,你应该考虑这个。你为什么要等待一个int被接收,并且只有一部分int被发送?这绝不应该发生。如果你想发送不同类型的数据,你应该首先包含一些标题字节,告诉接收方接下来将接收什么样的数据,以便知道如何处理它以及如何处理它。

+0

确实,阻塞是一种自然行为。 – 2010-10-29 13:43:27

1

这个异常大概只有当连接的另一端关闭了这个套接字时才会抛出异常。否则,接收方没有迹象表明没有更多的数据会来,所以它等待(当你叫readInt时,你告诉它至少得到4个字节)。你将不得不读取字节并将它们解析到应用程序块中。

0

您正在使用的类形成java.io包的一部分,该包执行阻塞 I/O。正确的解决方案是切换到使用java.nio中定义的非阻塞I/O类。被警告说编写一个非阻塞的I/O应用程序并不重要。但是,它是避免让I/O线程无限期阻塞的唯一解决方案。

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

+0

不,当设备没有发送一个正确的解决方案时,不要尝试读取一个4字节的整数。 – EJP 2010-11-02 09:00:38

+0

@EJP:这会让您的应用程序受到设备的支配;如果设备存在错误或者它只是脱机/不可访问(留下悬挂的TCP套接字),则应用程序线程将无限期阻塞。因此,使用阻塞I/O不是一个优雅的解决方案。 – Adamski 2010-11-02 14:36:14

+0

这是相当不真实的。只需设置读取超时。然后,应用程序将仅阻塞超时的长度,然后抛出SocketTimeoutException。这种情况并没有使java.nio成为“正确的解决方案”。这是很多人之一。 – EJP 2010-11-02 23:15:29

0

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