我正在开发一个 Java 标准版应用程序。
该应用程序的用户有一个化名。
我的应用程序可以用作服务器。
在这种情况下,一个线程运行以接受来自应用程序客户端实例的连接。
接受连接后,客户端用户将注册到列表中。
服务器线程定期向每个客户端实例广播用户列表。
客户端实例根据服务器实例发送的数据更新其自己的用户列表。
我遇到了一个不系统的问题。
我认为我的问题与 TCP 协议有关。
在我的测试期间,服务器和客户端实例在同一台计算机上运行。
我使用 RawCap 和 Wireshark 捕获了在 127.0.0.1 发送和接收的数据帧。
这是发生问题的场景:
用户 U1 作为服务器执行应用程序。
用户 U2 作为客户端执行应用程序并连接到服务器实例。
服务器实例接受连接。
我已经捕获了用于建立连接的帧。
tns-adv 表示客户端实例,tns-server 表示服务器实例。
这是框架: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=1客户端实例将 U2 的假名发送到服务器实例。
U2的化名是“Moi”。
假名后跟一个回车符和一个换行符。
这是框架:tns-adv > tns-server [PSH, ACK] Seq=1 Ack=1 Len=5
服务器实例接收 U2 的化名。TCP 确认会自动发送到客户端实例。
这是框架:tns-server > tns-adv [ACK] Seq=1 Ack=6
服务器实例将 U2 注册到它自己的用户列表中。
U2 注册在第二个位置。
服务器将 U2 的位置 (2) 发送到客户端实例。
该位置后跟一个回车符和一个换行符。
这是框架:tns-server > tns-adv [PSH, ACK] Seq=1, Ack=6 Len=3
客户端实例接收 U2 的位置并将 U2 注册到它自己的列表中的第二个位置。
TCP 确认会自动发送到服务器实例。
这是框架:tns-adv > tns-server [ACK] Seq=6 Ack=4
服务器实例向客户端实例发送通知。
该通知用于向客户端实例发送信号以发回证明客户端实例仍然可用的数据。
通知是“[DISPO ?]”。
通知后跟回车符和换行符。
这是框架:tns-server > tns-adv [PSH, ACK] Seq=4 Ack=6 Len=11
TCP 确认会自动从客户端实例发送到服务器实例。
但是客户端实例上的以下 Java 命令块: bufferedReader.readLine()
该命令应该接收服务器通知。
在服务器实例上捕获了一个异常,它的消息是:连接重置。
我已经捕获了重置连接的帧。
但我不知道为什么这个帧是从客户端实例发送的。
这是框架:tns-adv > tns-server [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.