UDP客户端/服务端程序字段接收错误问题排查
UDP通信程序字段接收错误排查与修复
我开发了两个Java程序实现UDP通信,运行时出现逻辑错误:输入"Hello"后,程序提示输入用户名,但输入的用户名被识别成了密码。
实际输出
What is your initial message Hello Welcome to Keene State Server, what is your username? Alice Incorrect password. Please try again.
期望输出
What is your initial message Hello Welcome to Keene State Server, what is your username? Alice User name is OK, what is your password? 123456 Password is OK, you are now connected to the network
原代码
客户端代码
import java.io.*; import java.net.*; class ClientProcess { public static void main(String args[]) throws Exception { //Asks user for what their initial message is System.out.println("What is your initial message"); BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in)); while(true) { //create a new client socket and Gets the IP address of the computer on which the other //process in running //in this case, it's localhost because both two processes (client and server) are running //on the same local host DatagramSocket clientSocket = new DatagramSocket(); InetAddress IPAddress = InetAddress.getByName("localhost"); byte[] sendData = new byte[1024]; byte[] receiveData = new byte[1024]; //the data message we will send is from the user input String username = inFromUser.readLine(); sendData = username.getBytes(); DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 5000); clientSocket.send(sendPacket); DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); clientSocket.receive(receivePacket); String response = new String(receivePacket.getData()).trim(); //if the response is good it will ask for the password if (response.equals("User name is OK, what is your password?")) { System.out.println("Please enter your password:"); String password = inFromUser.readLine(); sendData = password.getBytes(); sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 5000); clientSocket.send(sendPacket); receivePacket = new DatagramPacket(receiveData, receiveData.length); clientSocket.receive(receivePacket); response = new String(receivePacket.getData()).trim(); System.out.println(response); } else { System.out.println(response); } clientSocket.close(); } } }
服务器端代码
import java.io.*; import java.net.*; class ServerProcess { public static void main(String args[]) throws Exception { //In the server process, a DatagramSocket object must also be instantiated //and bound to a local port number which is 5000 in this case. DatagramSocket serverSocket = new DatagramSocket(5000); while(true) { byte[] receiveData = new byte[1024]; byte[] sendData = new byte[1024]; //Receives data messages sent to the server packet DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); serverSocket.receive(receivePacket); InetAddress IPAddress = receivePacket.getAddress(); int port = receivePacket.getPort(); String username = new String(receivePacket.getData()).trim(); String response = ""; //If stetment that takes the input and chooses what to display if (username.equals("Hello")) { response = "Welcome to the Server, what is your username?"; } else if (username.equals("Alice")) { response = "User name is OK, what is your password?"; } else { response = "Invalid username. Please try again."; } sendData = response.getBytes(); DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port); serverSocket.send(sendPacket); receivePacket = new DatagramPacket(receiveData, receiveData.length); serverSocket.receive(receivePacket); IPAddress = receivePacket.getAddress(); port = receivePacket.getPort(); String password = new String(receivePacket.getData()).trim(); if (password.equals("123456")) { response = "Password is OK, you are now connected to the network"; } else { response = "Incorrect password. Please try again."; } sendData = response.getBytes(); sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port); serverSocket.send(sendPacket); } } }
错误原因
- 服务器端逻辑强制循环接收两次数据:不管第一次的响应是什么,服务器每次循环都会先接收一个数据包,返回响应后立刻阻塞等待第二个数据包。当客户端发送"Hello"后,服务器返回欢迎信息,随即等待下一个包,此时客户端发送的用户名被服务器直接当作密码处理。
- 客户端流程混乱:客户端用死循环重复创建Socket,变量命名混淆(把初始消息赋值给
username),收到服务器欢迎信息后没有正确触发用户名输入流程,而是直接进入下一次循环发送用户名,导致服务器误判。
修复后的代码
客户端代码
import java.io.*; import java.net.*; class ClientProcess { public static void main(String args[]) throws Exception { System.out.println("What is your initial message"); BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in)); // 仅创建一次Socket,避免重复资源开销 DatagramSocket clientSocket = new DatagramSocket(); InetAddress IPAddress = InetAddress.getByName("localhost"); byte[] sendData = new byte[1024]; byte[] receiveData = new byte[1024]; // 发送初始消息 String initialMsg = inFromUser.readLine(); sendData = initialMsg.getBytes(); DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 5000); clientSocket.send(sendPacket); // 接收服务器欢迎响应并打印 DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); clientSocket.receive(receivePacket); String response = new String(receivePacket.getData()).trim(); System.out.println(response); // 输入并发送用户名 String username = inFromUser.readLine(); sendData = username.getBytes(); sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 5000); clientSocket.send(sendPacket); // 接收用户名验证响应并打印 receivePacket = new DatagramPacket(receiveData, receiveData.length); clientSocket.receive(receivePacket); response = new String(receivePacket.getData()).trim(); System.out.println(response); // 用户名验证通过后,输入并发送密码 if (response.equals("User name is OK, what is your password?")) { String password = inFromUser.readLine(); sendData = password.getBytes(); sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 5000); clientSocket.send(sendPacket); // 接收密码验证响应并打印 receivePacket = new DatagramPacket(receiveData, receiveData.length); clientSocket.receive(receivePacket); response = new String(receivePacket.getData()).trim(); System.out.println(response); } clientSocket.close(); } }
服务器端代码
import java.io.*; import java.net.*; class ServerProcess { public static void main(String args[]) throws Exception { DatagramSocket serverSocket = new DatagramSocket(5000); byte[] receiveData = new byte[1024]; byte[] sendData = new byte[1024]; while(true) { // 第一步:接收初始消息 DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); serverSocket.receive(receivePacket); InetAddress IPAddress = receivePacket.getAddress(); int port = receivePacket.getPort(); String initialMsg = new String(receivePacket.getData()).trim(); String response = ""; if (initialMsg.equals("Hello")) { response = "Welcome to Keene State Server, what is your username?"; } else { response = "Invalid initial message. Please start with Hello."; } sendData = response.getBytes(); DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port); serverSocket.send(sendPacket); // 初始消息正确,才继续处理用户名 if (response.startsWith("Welcome")) { // 第二步:接收用户名 receivePacket = new DatagramPacket(receiveData, receiveData.length); serverSocket.receive(receivePacket); IPAddress = receivePacket.getAddress(); port = receivePacket.getPort(); String username = new String(receivePacket.getData()).trim(); if (username.equals("Alice")) { response = "User name is OK, what is your password?"; } else { response = "Invalid username. Please try again."; } sendData = response.getBytes(); sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port); serverSocket.send(sendPacket); // 用户名正确,才继续处理密码 if (response.startsWith("User name is OK")) { // 第三步:接收密码 receivePacket = new DatagramPacket(receiveData, receiveData.length); serverSocket.receive(receivePacket); IPAddress = receivePacket.getAddress(); port = receivePacket.getPort(); String password = new String(receivePacket.getData()).trim(); if (password.equals("123456")) { response = "Password is OK, you are now connected to the network"; } else { response = "Incorrect password. Please try again."; } sendData = response.getBytes(); sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port); serverSocket.send(sendPacket); } } } } }
修改说明
- 客户端:移除无效死循环,按照"初始消息→用户名→密码"的顺序线性执行;变量命名更清晰;只创建一次Socket优化资源使用。
- 服务器:采用条件嵌套的分步接收逻辑,只有当前步骤验证通过后,才会触发下一个数据接收操作;修正欢迎消息文本与客户端期望一致,避免匹配失败;流程逻辑与客户端完全对齐。
内容的提问来源于stack exchange,提问作者Ethan
相关产品推荐
相关产品推荐

