2010-10-29 117 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字符串?