Сброс соединения + Java SE + TCP
Я разрабатываю приложение Java Standard Edition.
Пользователь приложения имеет псевдоним.
Мое приложение может быть использовано в качестве сервера.
В таком случае поток выполняется для приема соединений от клиентских экземпляров приложения.
Когда соединение принято, клиентский пользователь регистрируется в списке.
Поток сервера регулярно передает список пользователей каждому экземпляру клиента.
Экземпляр клиента обновляет свой список пользователей на основе данных, отправленных экземпляром сервера.
У меня проблема не систематически.
Я думаю, что моя проблема связана с протоколом TCP.
Во время моих тестов экземпляры сервера и клиента работают на одном компьютере.
Я захватил кадры данных, отправленных и полученных на 127.0.0.1 с использованием RawCap и Wireshark.
Вот сценарий, где возникает проблема:
Пользователь U1 выполняет приложение как сервер.
Пользователь U2 выполняет приложение как клиент и подключается к экземпляру сервера.
Экземпляр сервера принимает соединение.
Я захватил кадры, используемые для установления соединения.
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Экземпляр клиента отправляет псевдоним U2 на экземпляр сервера.
Псевдоним U2 - "Мой".
За псевдонимом следует возврат каретки и символы перевода строки.
Вот кадр:tns-adv> tns-сервер [PSH, ACK] Seq=1 Ack=1 Len=5
Экземпляр сервера получает псевдоним U2. Подтверждение TCP автоматически отправляется клиентскому экземпляру.
Вот кадр:tns-сервер> tns-adv [ACK] Seq=1 Ack=6
Экземпляр сервера регистрирует U2 в своем собственном списке пользователей.
U2 зарегистрирован на второй позиции.
Сервер отправляет позицию U2 (2) в экземпляр клиента.
За позицией следует возврат каретки и символы перевода строки.
Вот кадр:tns-сервер> tns-adv [PSH, ACK] Seq=1, Ack=6 Len=3
Экземпляр клиента получает позицию U2 и регистрирует U2 в своем собственном списке на второй позиции.
Подтверждение TCP автоматически отправляется на экземпляр сервера.
Вот кадр:tns-adv> tns-сервер [ACK] Seq=6 Ack=4
Экземпляр сервера отправляет уведомление экземпляру клиента.
Уведомление используется, чтобы сигнализировать экземпляру клиента об отправке данных, доказывая, что экземпляр клиента все еще доступен.
Уведомление "[DISPO?]".
За уведомлением следует возврат каретки и символы перевода строки.
Вот кадр:tns-сервер> tns-adv [PSH, ACK] Seq=4 Ack=6 Len=11
Подтверждение 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 для клиента, который уже отказался.