TCP-соединение сбрасывается после отправки срочных данных - PullRequest
2 голосов
/ 20 октября 2011

В настоящее время я отлаживаю два Java-приложения, которые обмениваются данными через TCP-соединение.

Одно из приложений, TCP-клиент, периодически отправляет срочные данные другому, TCP-серверу, вызывая Разъем # sendUrgentData (INT) .На 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 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("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 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("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();
    }
}

Может ли кто-нибудь объяснить, что здесь происходит?

Спасибо.

Ответы [ 2 ]

1 голос
/ 20 октября 2011

Я предполагаю, что вы действительно правильно получаете срочные данные в приложении, которое выходит из строя, и что данные соответствуют вашим ожиданиям?

Есть много причин для этого, особенно если вы пытаетесь сделать это в кроссплатформенной ситуации: в TCP есть два противоречивых описания того, как работают срочные данные, RFC 793 , в которых подробно говорится, что TCP говорит что указатель срочности указывает байт, который следует за срочными данными, но RFC 1122 исправляет это и утверждает, что указатель срочности указывает окончательный байт срочных данных. Это приводит к проблемам совместимости, если один узел использует определение RFC 793, а другой - определение RFC 1122.

Итак, сначала убедитесь, что ваше приложение действительно получает правильный байт срочных данных. Да, я сказал, байт, есть большая сложность совместимости в том, что Windows поддерживает только один байт внеполосных данных, тогда как RFC 1122 указывает, что TCP ДОЛЖЕН поддерживать последовательности байтов срочных данных любой длины. Windows также не указывает, как или будет ли она буферизовать последующие внеполосные данные, поэтому, если вы слишком медленно читаете байт срочных данных и приходит другой байт срочных данных, один из байтов может быть потерян; хотя наши тесты показали, что Windows действительно буферизирует срочные данные. Это все делает использование внеполосной сигнализации с использованием срочных данных несколько ненадежным в Windows с TCP.

И затем возникают другие проблемы, если вы используете перекрывающийся ввод-вывод.

Я рассмотрел это немного глубже, хотя и с точки зрения C ++, здесь: http://www.serverframework.com/asynchronousevents/2011/10/out-of-band-data-and-overlapped-io.html

0 голосов
/ 20 октября 2011

Срочные данные принимаются в потоке Java, что приведет к потере порядка в потоке данных.Вероятно, получатель не понял данные не в порядке и закрыл соединение.Затем вы продолжали писать в него, и это может привести к «сбросу соединения по пиру».Морально то, что вы не можете использовать срочные данные TCP в Java, если получатель не очень тщательно написан.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...