我正在开发Java Standard Edition应用程序 该应用程序的用户有一个假名。
我的应用程序可以用作服务器 在这种情况下,线程运行以接受来自应用程序的客户端实例的连接 当接受连接时,客户端用户被注册到列表中 服务器线程定期向每个客户端实例广播用户列表 客户端实例从服务器实例发送的数据更新其自己的用户列表。
我没有系统地解决问题 我认为我的问题与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.
答案 0 :(得分:0)
[RST,ACK]会因为您的客户端不再侦听套接字而发生。代理可能已崩溃或超时并放弃连接。操作系统可能会为已经放弃的客户端发送RST ACK。