Сброс соединения + Java SE + TCP

Я разрабатываю приложение Java Standard Edition.
Пользователь приложения имеет псевдоним.

Мое приложение может быть использовано в качестве сервера.
В таком случае поток выполняется для приема соединений от клиентских экземпляров приложения.
Когда соединение принято, клиентский пользователь регистрируется в списке.
Поток сервера регулярно передает список пользователей каждому экземпляру клиента.
Экземпляр клиента обновляет свой список пользователей на основе данных, отправленных экземпляром сервера.

У меня проблема не систематически.
Я думаю, что моя проблема связана с протоколом TCP.
Во время моих тестов экземпляры сервера и клиента работают на одном компьютере.
Я захватил кадры данных, отправленных и полученных на 127.0.0.1 с использованием RawCap и Wireshark.

Вот сценарий, где возникает проблема:

  1. Пользователь U1 выполняет приложение как сервер.

  2. Пользователь U2 выполняет приложение как клиент и подключается к экземпляру сервера.

  3. Экземпляр сервера принимает соединение.
    Я захватил кадры, используемые для установления соединения.
    tns-adv означает экземпляр клиента, а tns-server означает экземпляр сервера.
    Вот кадры:

    tns-adv> tns-server [SYN] Seq = 0
    tns-сервер> tns-adv [SYN, ACK] Seq = 0 Ack = 1
    tns-adv> tns-сервер [ACK] Seq=1 Ack=1

  4. Экземпляр клиента отправляет псевдоним U2 на экземпляр сервера.
    Псевдоним U2 - "Мой".
    За псевдонимом следует возврат каретки и символы перевода строки.
    Вот кадр:

    tns-adv> tns-сервер [PSH, ACK] Seq=1 Ack=1 Len=5

  5. Экземпляр сервера получает псевдоним U2. Подтверждение TCP автоматически отправляется клиентскому экземпляру.
    Вот кадр:

    tns-сервер> tns-adv [ACK] Seq=1 Ack=6

  6. Экземпляр сервера регистрирует U2 в своем собственном списке пользователей.
    U2 зарегистрирован на второй позиции.
    Сервер отправляет позицию U2 (2) в экземпляр клиента.
    За позицией следует возврат каретки и символы перевода строки.
    Вот кадр:

    tns-сервер> tns-adv [PSH, ACK] Seq=1, Ack=6 Len=3

  7. Экземпляр клиента получает позицию U2 и регистрирует U2 в своем собственном списке на второй позиции.
    Подтверждение TCP автоматически отправляется на экземпляр сервера.
    Вот кадр:

    tns-adv> tns-сервер [ACK] Seq=6 Ack=4

  8. Экземпляр сервера отправляет уведомление экземпляру клиента.
    Уведомление используется, чтобы сигнализировать экземпляру клиента об отправке данных, доказывая, что экземпляр клиента все еще доступен.
    Уведомление "[DISPO?]".
    За уведомлением следует возврат каретки и символы перевода строки.
    Вот кадр:

    tns-сервер> tns-adv [PSH, ACK] Seq=4 Ack=6 Len=11

  9. Подтверждение TCP автоматически отправляется экземпляру сервера от экземпляра клиента.
    Но следующие экземпляры Java-команд на клиентском экземпляре: bufferedReader.readLine()
    Эта команда должна получить уведомление от сервера.
    Исключительная ситуация обнаружена на экземпляре сервера, и его сообщение: Сброс соединения.
    Я захватил кадр сброса соединения.
    Но у меня нет никаких идей, почему этот кадр отправляется из экземпляра клиента.
    Вот кадр:

    tns-adv> tns-сервер [RST, ACK] Seq=6 Ack=15

Изменить: я добавил следующие фрагменты кода в ответ на комментарии

Соответствующие команды Java, выполненные в потоке на экземпляре клиента

// Connect to the server instance.
socket = new Socket(adrIpv4, numPortSvr);

// Instance an object to read data sent by the server instance.
inputStream = socket.getInputStream();
inputStreamReader = new InputStreamReader(inputStream);
bufferedReader = new BufferedReader(inputStreamReader);

// Instance an object to send data to the server instance.
outputStream = socket.getOutputStream();
outputStreamWriter = new OutputStreamWriter(outputStream);
bufferedWriter = new BufferedWriter(outputStreamWriter);

// Send my pseudonym to the server instance.
// Frame sent : Frame 4.
bufferedWriter.write(monJoueur.getPseudonyme());
bufferedWriter.newLine();
bufferedWriter.flush();

// Wait for my position in the user list from the server instance.
// Frame received : Frame 6.
chaine = bufferedReader.readLine();

// Register myself into this instance's user list at the position received from the server instance. 
partie.setJoueurAtPosition(monJoueur, position);

// Wait for an availability request from the server instance.
// Frame expected : Frame 8.
// That command blocks and the reset frame 9 is sent to the server instance.
chaine = bufferedReader.readLine();

Соответствующие команды Java, выполняемые в потоке на экземпляре сервера

// Create the server socket.
// Allocate automatically a free port number.
socketServeur = new ServerSocket(0);
partie.setSocketServeur(socketServeur);

// Set the max time the server instance can wait for a connection from a client instance : 500 milliseconds.
socketServeur.setSoTimeout(ThreadCreerPartie.DUREE_ATTENTE_CONNEX);

// Wait 500ms max for a connection from a client instance.
socket = socketServeur.accept();

// Instance an object to read data sent by the client instance.
inputStream = socket.getInputStream();
inputStreamReader = new InputStreamReader(inputStream);
bufferedReader = new BufferedReader(inputStreamReader);

// Instance an object to send data to the client instance.
outputStream = socket.getOutputStream();
outputStreamWriter = new OutputStreamWriter(outputStream);
bufferedWriter = new BufferedWriter(outputStreamWriter);

// Wait for the client's pseudonym.
// Frame received : Frame 4.
chaine = bufferedReader.readLine();

// Registrer the client into this instance's user list at the first available position.
positionJoueur = partie.inscrireJoueur(socket, chaine);

// Send the client's position in the user list to the client instance.
// Frame sent : Frame 6.
bufferedWriter.write(String.valueOf(positionJoueur));
bufferedWriter.newLine();
bufferedWriter.flush();

// Send an availability request to the client instance.
// Frame sent : Frame 8.
bufferedWriter.write("[DISPO ?]");
bufferedWriter.newLine();
bufferedWriter.flush();

// Receive the availability proof from the client instance.
chaine = null;
chaine = bufferedReader.readLine(); //< Raises an exception with the message : Connection reset.

1 ответ

[RST, ACK] придет, потому что ваш клиент больше не прослушивает сокет. Агент, возможно, потерпел крах или прервал тайм-аут и отказался от соединения. ОС скорее всего отправляет RST ACK для клиента, который уже отказался.

Другие вопросы по тегам