I am developing a Java Standard Edition application.
The user of the application has a pseudonym.
My application can be used as a server.
In such a case a thread runs to accept connections from client instances of the application.
When a connection is accepted then the client user is registered into a list.
The server thread broadcasts regularly the list of users to every client instance.
A client instance updates its own list of users from data sent by the server instance.
I have got a problem not systematically.
I think my problem is relative to the TCP protocol.
The server and the client instances are running on the same computer during my tests.
I have captured frames of data sent to and received at 127.0.0.1 by using RawCap and Wireshark.
Here is the scenario where the problem occurs :
A user U1 executes the application as a server.
A user U2 executes the application as a client and connects to the server instance.
The server instance accepts the connection.
I have captured the frames used to etablish the connection.
tns-adv means the client instance and tns-server means the server instance.
Here are the frames :tns-adv > tns-server [SYN] Seq=0
tns-server > tns-adv [SYN, ACK] Seq=0 Ack=1
tns-adv > tns-server [ACK] Seq=1 Ack=1The client instance send U2's pseudonym to the server instance.
U2's pseudonym is "Moi".
The pseudonym is followed by a carriage return and a linefeed characters.
Here is the frame :tns-adv > tns-server [PSH, ACK] Seq=1 Ack=1 Len=5
The server instance receives U2's pseudonym. A TCP acknowlegment is automatically sent to the client instance.
Here is the frame :tns-server > tns-adv [ACK] Seq=1 Ack=6
The server instance registers U2 into its own user list.
U2 is registered at the second position.
The server sends U2's position (2) to the client instance.
The position is followed by a carriage return and a linefeed characters.
Here is the frame :tns-server > tns-adv [PSH, ACK] Seq=1, Ack=6 Len=3
The client instance receives U2's position and registers U2 into its own list at the second position.
A TCP acknowlegment is automatically sent to the server instance.
Here is the frame :tns-adv > tns-server [ACK] Seq=6 Ack=4
The server instance sends a notification to the client instance.
The notification is used to signal a client instance to send back data proving the client instance is still available.
The notification is "[DISPO ?]".
The notification is followed by a carriage return and a linefeed characters.
Here is the frame :tns-server > tns-adv [PSH, ACK] Seq=4 Ack=6 Len=11
A TCP acknowlegment is automatically sent to the server instance from the client instance.
But the following Java command blocks on the client instance : bufferedReader.readLine()
This command is supposed to receive the server notification.
An exception is caught on the server instance and its message is : Connection reset.
I have captured the frame resetting the connection.
But I do not have any ideas why this frame is sent from the client instance.
Here is the frame :tns-adv > tns-server [RST, ACK] Seq=6 Ack=15
Edit : I have added the following code snippets in response to comments
Relevant java commands executed on a thread on the client instance
// 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();
Relevant java commands executed on a thread on the server instance
// 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.