2 Stimmen

Die TCP-Verbindung wird nach dem Senden von dringenden Daten zurückgesetzt

Ich debugge derzeit zwei Java-Anwendungen, die Daten über eine TCP-Verbindung austauschen.

Eine der Anwendungen, der TCP-Client, sendet periodisch dringende Daten an den anderen, den TCP-Server, indem er Socket#sendUrgentData(int) aufruft. Beim 18. Versuch, die dringenden Daten zu senden, wirft der TCP-Client die folgende Ausnahme

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

Der TCP-Server wirft diese Ausnahme

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

Ich glaube, die Ausnahmen werden durch den Versuch verursacht, auf eine geschlossene Verbindung/ein geschlossenes Socket zu schreiben/lesen. Was ich nicht verstehe ist, warum die Verbindung oder das Socket nach dem Aufruf von sendUrgentData() 17 Mal geschlossen wird. Ich kann es wiederholen und es tritt immer nach 17 Mal auf.

Wenn ich den Client und den Server unter Windows ausführe, tritt das Problem auf. Wenn ich den Client und den Server unter Solaris ausführe, tritt das Problem nicht auf. Wenn ich den Client auf Solaris und den Server auf Windows ausführe, tritt das Problem auf. Wenn ich den Client auf Windows und den Server auf Solaris ausführe, tritt das Problem nicht auf. Das lässt mich denken, es könnte mit Windows zusammenhängen?

Bei Verwendung von Wireshark sehe ich den folgenden Datenverkehr auf der Verbindung

--> = vom TCP-Client zum TCP-Server
<-- = vom TCP-Server zum 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)

Ich habe einige einfache Testklassen geschrieben, die das Problem zeigen.

TCPServer.java IP_Address Port

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("GEBUNDEN/" + socket);
        Socket connection = socket.accept();
        System.out.println("VERBUNDEN/" + connection);
        int b;
        while ((b = connection.getInputStream().read()) != -1) {
            System.out.println("LESEN byte: " + b);
        }
        System.out.println("SCHLIEßEN ..");
        connection.close();
        socket.close();
}
}

TCPClient.java IP_Address Port 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("VERBUNDEN/"+socket);
        Timer urgentDataTimer = new Timer(true);
        urgentDataTimer.scheduleAtFixedRate(new TimerTask() 
        {       
            int n = 0;  
            public void run() {
                try {
                    System.out.println("SENDE DRINGENDE DATEN ("+(++n)+") ..");
                    socket.sendUrgentData(1);
                    System.out.println("GESCHICKT DRINGENDE DATEN");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, 1000, Integer.parseInt(args[2]));

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

Kann mir jemand erklären, was hier passiert?

Danke.

1voto

Len Holgate Punkte 20590

Ich gehe davon aus, dass Sie tatsächlich die dringenden Daten in der Anwendung korrekt empfangen, die fehlschlägt, und dass die Daten so sind, wie Sie es erwarten?

Es gibt viele Gründe, warum dies scheitern kann, insbesondere wenn Sie es in einer plattformübergreifenden Situation versuchen: Im TCP gibt es zwei widersprüchliche Beschreibungen, wie dringende Daten funktionieren, RFC 793, das TCP detailliert beschreibt, besagt, dass der Urgent Pointer das Byte angibt, das den dringenden Daten folgt, aber RFC 1122 korrigiert dies und gibt an, dass der Urgent Pointer das letzte Byte der dringenden Daten angibt. Dies führt zu Interoperabilitätsproblemen, wenn ein Peer die Definition von RFC 793 verwendet und der andere die Definition von RFC 1122 verwendet.

Bestätigen Sie daher zunächst, dass Ihre Anwendung tatsächlich das richtige Byte dringender Daten erhält. Ja, ich sagte Byte, denn in Windows unterstützt nur ein Byte von außerhalb der Banddaten, während RFC 1122 festlegt, dass TCP Sequenzen von dringenden Datenbytes beliebiger Länge unterstützen MUSS. Windows gibt auch nicht an, wie oder ob es nachfolgende außerhalb der Banddaten zwischenspeichert, sodass, wenn Sie langsam ein Byte dringender Daten lesen und ein weiteres Byte dringender Daten eintrifft, eines der Bytes verloren gehen kann; obwohl unsere Tests gezeigt haben, dass Windows dringende Daten zwischenspeichert. All dies macht die Verwendung von außerhalb der Band signalisierenden Daten, die dringende Daten verwenden, auf Windows mit TCP etwas unzuverlässig.

Und dann gibt es all die anderen Probleme, die auftreten, wenn Sie überlappende I / O verwenden.

Ich habe dies etwas ausführlicher behandelt, wenn auch aus einer C++-Perspektive, hier: http://www.serverframework.com/asynchronousevents/2011/10/out-of-band-data-and-overlapped-io.html

0voto

user207421 Punkte 297318

Dringende Daten werden in Java inline empfangen, was dazu führen würde, dass der Datenstrom durcheinander gerät. Wahrscheinlich hat der Empfänger die Daten außerhalb der Reihe nicht verstanden und die Verbindung geschlossen. Dann haben Sie weiterhin Daten geschrieben, was zu einem 'Verbindungsreset durch Peer' führen kann. Die Moral ist, dass Sie im Grunde genommen keine dringenden TCP-Daten in Java verwenden können, es sei denn, der Empfänger ist sehr sorgfältig geschrieben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X