簡體   English   中英

發送緊急數據后,TCP連接被重置

[英]TCP Connection is reset after sending urgent data

我目前正在調試兩個通過TCP連接交換數據的Java應用程序。

其中一個應用程序(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();
    }
}

有人可以解釋這里發生了什么嗎?

謝謝。

我假設您實際上在故障應用程序中正確接收了緊急數據,並且這些數據符合您的預期?

導致失敗的原因有很多,尤其是在跨平台的情況下嘗試時:在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

Java緊急接收緊急數據,這會使數據流混亂。 接收者可能不了解亂序數據並關閉了連接。 然后您繼續對其進行寫操作,這可能會導致“對等方重置連接”。 道德是除非您非常仔細地編寫了接收者,否則您基本上不能在Java中使用緊急TCP數據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM