2012-01-10 76 views
1

我曾經遇到過socket通信的問題Linux系統上的過程中永遠掛起,其通信過程是象下面這樣:客戶端發送郵件向服務器做一個計算任務,任務完成後等待來自服務器的結果消息。ObjectInputStream.readObject()socket通信

但是,如果任務花費很長時間(例如大約40分鐘),則客戶端會掛起等待結果消息,即使從服務器端,結果消息已被寫入套接字以響應客戶端,但是如果任務花費很少時間,例如一分鐘,它通常可以收到結果消息。另外,這個問題只發生在客戶環境中,通信過程在我們的測試環境中正常運行。

我一直懷疑的原因這個問題是插座的默認超時值是客戶環境和測試環境之間的不同,但後續的值是在這兩個環境相同,客戶端和服務器。

getSoTimeout:0 
getReceiveBufferSize:43690 
getSendBufferSize:8192 
getSoLinger:-1 
getTrafficClass:0 
getKeepAlive:false 
getTcpNoDelay:false 

在客戶端的代碼是這樣的:

Message msg = null; 
ObjectInputStream in = client.getClient().getInputStream(); 
//if no message readObject() will hang here 
while (true) { 
    try { 
    Object recObject = in.readObject(); 
    System.out.println("Client received msg."); 
    msg = (Message)recObject; 
    return msg; 
     }catch (Exception e) { 
    e.printStackTrace(); 
    return null; 
    } 
} 

代碼上服務器都喜歡,

ObjectOutputStream socketOutStream = getSocketOutputStream(); 
try { 
    MessageJobComplete msgJobComplete = new MessageJobComplete(reportFile, outputFile); 
    socketOutStream.writeObject(msgJobComplete); 
    }catch(Exception e) { 
    e.printStackTrace(); 
    } 

爲了解決這個問題,我已經添加了沖洗和復位方法,但問題依然存在:

ObjectOutputStream socketOutStream = getSocketOutputStream(); 
try { 
    MessageJobComplete msgJobComplete = new MessageJobComplete(reportFile, outputFile); 
    socketOutStream.flush(); 
    logger.debug("AbstractJob#reply to the socket"); 
    socketOutStream.writeObject(msgJobComplete); 
    socketOutStream.reset(); 
    socketOutStream.flush(); 
    logger.debug("AbstractJob#after Flush Reply"); 
}catch(Exception e) { 
    e.printStackTrace(); 
      logger.error("Exception when sending MessageJobComplete."+e.getMessage()); 
} 

所以,有誰知道我應該怎樣做才能解決這個問題。 我猜的原因是環境設置,但我不知道環境因素會影響套接字通信?

並採用TCP/IP protocal交流插座,問題與長時間工作的關係,所以什麼樣的價值觀有關TCP會影響socket通信的超時?

我有關日誌的分析後,我發現該消息被寫入到插座後,有沒有異常拋出/捕獲。但總是在15分鐘後,服務器端的objectInputStream.readObject()代碼片段中有例外,它用於接受來自客戶端的請求。但是,socket.getSoTimeout值爲0,因此引發超時異常是非常奇怪的。

{2012-01-09 17:44:13,908} ERROR java.net.SocketException: Connection timed out 
    at java.net.SocketInputStream.socketRead0(Native Method) 
    at java.net.SocketInputStream.read(SocketInputStream.java:146) 
    at sun.security.ssl.InputRecord.readFully(InputRecord.java:312) 
    at sun.security.ssl.InputRecord.read(InputRecord.java:350) 
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:809) 
    at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:766) 
    at sun.security.ssl.AppInputStream.read(AppInputStream.java:94) 
    at sun.security.ssl.AppInputStream.read(AppInputStream.java:69) 
    at java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2265) 
    at java.io.ObjectInputStream$BlockDataInputStream.peek(ObjectInputStream.java:2558) 
    at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2568) 
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1314) 
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:368) 

那麼爲什麼Connection Timed out異常被拋出?

+0

如果客戶端沒有收到,它的服務器可能沒有發送。我會確認你看到客戶端沒有收到的發送對象的日誌消息。 – 2012-01-10 07:57:14

+0

謝謝,但是日誌顯示對象已經發送,並且沒有檢測到任何異常,只是客戶端掛起,你知道如何檢查嗎? {2012-01-09 19:28:16,416} DEBUG AbstractJob#回覆socket {2012-01-09 19:28:16,422} DEBUG AbstractJob#沖洗後回覆 – 2012-01-11 00:53:35

+0

printStackTrace不會出現在日誌中,它們是寫入控制檯。如果您沒有將控制檯寫入文件,我會確保將異常寫入日誌。 – 2012-01-11 07:23:31

回答

2

此問題已解決。使用tcpdump捕獲消息流。我發現,雖然在應用程序級別,ObjectOutputStream.writeObject()方法被調用,在tcp級別,多次發現[TCP ReTransmission]

因此,我斷定連接可能已經死機,儘管使用netstat -an命令tcp連接狀態仍然是ESTABLISHED

所以我寫了一個測試應用程序,定期發送測試消息作爲來自服務器的心跳消息。然後這個問題就消失了。

1

java.io.InputStreamread()方法阻塞調用,這意味着他們在等待「永遠」,如果他們被稱爲當有流中沒有數據讀取。

這是完全預期的行爲,並根據javadoc中發佈的合同,如果服務器沒有響應。

如果你想要一個非阻塞讀取,使用java.nio.*類。

+0

感謝您的迴應,但實際上服務器已將對象寫入套接字以響應客戶端。所以我不知道客戶爲什麼不能收到。 – 2012-01-10 05:47:52

+0

如果客戶端沒有收到,它的服務器可能沒有發送。我會確認你看到客戶端沒有收到的發送對象的日誌消息。 – 2012-01-10 07:56:58