2011-10-20 53 views
2

我目前正在調試兩個通過TCP連接交換數據的Java應用程序。發送緊急數據後TCP連接重置

TCP客戶端之一通過調用Socket#sendUrgentData(int)定期將緊急數據發送給另一個TCP服務器。本月18日試圖發送緊急數據,TCP客戶機拋出以下異常

java.io.IOException:BrokenPipe 
    at java.net.PlainSocketImpl.socketSendUrgentData(Native Method) 
    at java.net.PlainSocketImpl.sendUrgentData(PlainSocketImpl.java:541) 
    at java.net.Socket.sendUrgentData(Socket.java:927) 

的TCP服務器拋出該異常

java.net.SocketException: Software caused connection abort: recv failed 
    at java.net.SocketInputStream.socketRead0(Native Method) 
    at java.net.SocketInputStream.read(Unknown Source) 
    at java.net.SocketInputStream.read(Unknown Source) 

我相信例外是通過嘗試寫入引起/讀到一個封閉的連接/插座。我不明白爲什麼連接或套接字在調用sendUrgentData()17次後關閉。我可以重複它,它總是在17次後發生。

如果我在Windows上運行客戶端和服務器,則會出現問題。如果我在Solaris上運行客戶端和服務器,則不會發生此問題。如果我在Solaris上運行客戶端並在Windows上運行服務器,則會出現問題。如果我在Windows上運行客戶機並在Solaris上運行服務器,則不會發生此問題。這讓我覺得它可能與Windows有關?

使用Wireshark的我看到

--> = from TCP client to TCP server 
<-- = from TCP server to TCP client 

--> [PSH, ACK, URG] (Seq=1, Ack=1) 
<-- [ACK] (Seq=1, Ack=2) 
--> [PSH, ACK, URG] (Seq=2, Ack=1) 
<-- [ACK] (Seq=1, Ack=3) 
... 
--> [PSH, ACK, URG] (Seq=17, Ack=1) 
<-- [RST, ACK] (Seq=1, Ack=18) 

我寫了一些簡單的測試類,這表明這一問題的連接以下網絡通信。

TCPServer.java IP_ADDRESS端口

public class TCPServer 
{ 
    public static void main(String[] args) throws Exception 
    { 
     ServerSocket socket = new ServerSocket(); 
     socket.bind(new InetSocketAddress(args[0], Integer.parseInt(args[1]))); 
     System.out.println("BOUND/" + socket); 
     Socket connection = socket.accept(); 
     System.out.println("CONNECTED/" + connection); 
     int b; 
     while ((b = connection.getInputStream().read()) != -1) { 
      System.out.println("READ byte: " + b); 
     } 
     System.out.println("CLOSING .."); 
     connection.close(); 
     socket.close(); 
} 
} 

TCPClient.java IP_ADDRESS端口Interval_Between_Urgent_Data

public class TCPClient 
{ 
    public static void main(String[] args) throws Exception 
    { 
     final Socket socket = new Socket(); 
     socket.connect(new InetSocketAddress(InetAddress.getByName(args[0]), Integer.parseInt(args[1]))); 
     System.out.println("CONNECTED/"+socket); 
     Timer urgentDataTimer = new Timer(true); 
     urgentDataTimer.scheduleAtFixedRate(new TimerTask() 
     {  
      int n = 0; 
      public void run() { 
       try { 
        System.out.println("SENDING URGENT DATA ("+(++n)+") .."); 
        socket.sendUrgentData(1); 
        System.out.println("SENT URGENT DATA"); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     }, 1000, Integer.parseInt(args[2])); 

     int b; 
     while ((b = socket.getInputStream().read()) != 1) { 
      System.out.println("READ byte: " + b); 
     } 
     System.out.println("CLOSING .."); 
     urgentDataTimer.cancel(); 
     socket.close(); 
    } 
} 

有人能解釋這裏發生了什麼?

謝謝。

回答

0

緊急數據由Java在線接收,這會導致數據流出現亂序。接收者可能不瞭解無序數據並關閉連接。然後你一直寫信給它,並且可能會導致'通過對等方重置連接'。道德是你基本上不能使用Java中的緊急TCP數據,除非接收器是非常仔細的編寫的。

1

我假設你實際上正確地接收到失敗的應用程序中的緊急數據,並且數據如你所期望的那樣?

這有很多原因導致失敗,特別是如果你在跨平臺的情況下嘗試它:在TCP中有兩個衝突的數據工作原理的描述,RFC 793其中詳細說明TCP表示緊急指針指示緊跟在緊急數據後面的字節,但是RFC 1122糾正了這一點,並指出緊急指針指示緊急數據的最終字節。如果一個對等方使用RFC 793定義,而另一個使用RFC 1122定義,則會導致互操作性問題。

因此,首先確認您的應用程序實際上是獲取正確的緊急數據字節。是的,我說的字節,有更多的兼容性複雜性,因爲Windows只支持單個字節的帶外數據,而RFC 1122指定TCP必須支持任意長度的緊急數據字節序列。Windows也沒有指定如何或者是否會緩衝後續的帶外數據,所以如果讀取一個緊急數據字節的速度很慢,另一個緊急數據字節到達,那麼其中一個字節可能會丟失;儘管我們的測試顯示Windows確實緩衝了緊急數據。這一切都使得使用帶有TCP的Windows上的緊急數據在帶有某些不可靠的帶外信令上的使用成爲可能。

然後,如果碰巧使用重疊I/O,還有其他所有問題。

我在一個小更深入覆蓋這一點,儘管是從一個C++的角度來看,在這裏:http://www.serverframework.com/asynchronousevents/2011/10/out-of-band-data-and-overlapped-io.html

+0

這是在Java中所有內聯。 – EJP

+0

感謝您的答案。由於[setOOBInline()](http://download.oracle.com/javase/6/docs/api/java/net/Socket.html#setOOBInline%28boolean%29))沒有收到緊急數據設置(false)。緊急數據僅發送以防止在一段時間不活動後斷開連接。設置[setKeepAlive](http://download.oracle.com/javase/6/docs/api/java/net/Socket.html#setKeepAlive%28boolean%29))將是一個更好的解決方案。 如果我設置了setOOBInline()(true),則不會發生斷開連接並收到正確的字節。 – Stirls

+0

爲什麼你使用緊急數據呢?只需發送應用程序級別的ping消息。緊急數據只有在您有大量排隊等待處理(或發送)的數據時纔有用,並且您希望立即通知另一端,而不是在處理完所有數據之後通知另一端。爲了保持活力,情況並非如此;根據定義,您沒有任何待處理的數據,並且可以正常發送應用程序級別的消息。由於RFC不匹配和平臺問題,恕我直言,給出了緊急數據的問題,我很好地解決了這個問題。 –