【发布时间】:2019-05-26 23:36:04
【问题描述】:
我在这里有一个相当复杂的问题,希望理解我的代码不会成为这样的问题。
我正在用 Java 编写一个基于 UDP 和 TCP 通信的程序。 服务器正在监听多个 UDP 端口(1. 端口的数量和数量由用户在程序参数中给出;2. 为每个端口创建一个线程)用于来自客户端的数据包(可能有多个尝试发送一次数据包到服务器)。每个数据包都包含客户端 ID、发送此数据包的客户端的消息和 UDP 端口号。服务器接收到数据包,将消息放入 HashMap 中(客户端 ID 是键,发送的消息存储在字符串列表中)。在收到每个数据包时,服务器检查字符串列表是否从指定客户端发送的消息与密码匹配。如果消息的顺序正确,Server 会发送一个生成的端口号用于与发送正确密码的 Client 进行 TCP 通信,打开 ServerSockets,它们执行简单的通信,然后 Client 关闭。
现在,客户端应该能够将他的消息发送到各个端口。例如,服务器正在侦听端口 2000 和 3000。客户端应该能够向端口 2000 发送 2 条消息,并在端口 3000 上发送另外两条消息。但是,服务器似乎只在第一个打开的端口上接收消息。
如果客户端在一个端口上发送所有消息,一切正常。
这里是服务器类:
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
public class Server {
static int portsOpenedQuantity;
static HashMap<String, List<String>> packetsReceived = new HashMap<>();
static List<Integer> portsTCP = new ArrayList<>();
public static void main(String[] args) {
portsOpenedQuantity = args.length;
List<String> listOfPorts = new ArrayList<>();
for(int i = 0; i < portsOpenedQuantity; ++i)
if(!listOfPorts.contains(args[i]) && (Integer.parseInt(args[i]) > 1024))
listOfPorts.add(args[i]);
for(int i = 0; i < listOfPorts.size(); ++i) {
final int j = i;
System.out.println("SERVER listening on port: " + listOfPorts.get(j));
Thread listeningPort = new Thread(new Runnable() {
@Override
public void run() {
synchronized (packetsReceived){
try {
byte[] packetReceived = new byte[256];
DatagramSocket ds = new DatagramSocket(Integer.parseInt(listOfPorts.get(j)));
DatagramPacket dp = new DatagramPacket(packetReceived, 256);
while(true){
ds.receive(dp);
List<String> sequence = new ArrayList<>();
System.out.println("SERVER received a packet");
String msgReceived = new String(dp.getData(), 0, dp.getLength());
String[] separatedMsg = msgReceived.split(" ");
int portUDPNumber = Integer.parseInt(separatedMsg[2]);
System.out.println("Id: " + separatedMsg[0]);
System.out.println("Value: " + separatedMsg[1]);
System.out.println("Port UDP: " + separatedMsg[2]);
if(packetsReceived.containsKey(separatedMsg[0])) {
sequence = packetsReceived.get(separatedMsg[0]);
packetsReceived.remove(separatedMsg[0]);
System.out.println(separatedMsg[1]);
sequence.add(separatedMsg[1]);
System.out.println(sequence);
packetsReceived.put(separatedMsg[0], sequence);
} else {
System.out.println(sequence);
sequence.add(separatedMsg[1]);
packetsReceived.put(separatedMsg[0], sequence);
}
String sequenceResult = "";
for(int k = 0; k < sequence.size(); ++k) {
sequenceResult += sequence.get(k);
}
System.out.println(sequenceResult);
if(sequenceResult.equals("!@#$")){
System.out.println("Connecting via TCP...");
int portNumber = (int)((Math.random()*100)+5000);
boolean portAvailable = true;
ServerSocket ss = null;
System.out.println("TCP port number: " + portNumber);
while(portAvailable) {
try{
ss = new ServerSocket(portNumber);
portsTCP.add(portNumber);
portAvailable = false;
} catch(Exception e) {
portAvailable = true;
portNumber++;
}
}
System.out.println("socket number aquired");
String portNr = portNumber+"";
byte[] portNrToSend = portNr.getBytes();
dp = new DatagramPacket(portNrToSend, portNrToSend.length, InetAddress.getByName("localhost"), portUDPNumber);
System.out.println("Datagram created");
ds.send(dp);
System.out.println("Datagram sent");
Socket s = ss.accept();
System.out.println("Port number sent to: " + portUDPNumber);
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
String msgFromClient = in.readLine();
System.out.println("Message from client: " + msgFromClient);
out.println("I received your message");
in.close();
out.close();
s.close();
ss.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
listeningPort.start();
}
}
}
还有客户端类:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
public class Client {
InetAddress ip;
String idClient;
List<Integer> portsUDP = new ArrayList<>();
String sequence;
public Client(String[] args) {
try {
ip = InetAddress.getByName(args[0]);
idClient = args[1];
for(int i = 2; i < args.length; ++i)
portsUDP.add(Integer.parseInt(args[i]));
this.sequence = "!@#$";
DatagramSocket ds = new DatagramSocket();
DatagramPacket dp = null;
for(int i = 0; i < portsUDP.size(); ++i) {
byte[] toSend = new byte[256];
String msgToSend = idClient + " " + sequence.charAt(i) + " " + ds.getLocalPort();
System.out.println("CLIENT named as: " + idClient + " sends a message: " + sequence.charAt(i) + " " + ds.getLocalPort());
toSend = msgToSend.getBytes();
dp = new DatagramPacket(toSend, toSend.length, ip, portsUDP.get(i));
ds.send(dp);
System.out.println("CLIENT: " + idClient + " sent a packet");
toSend = new byte[256];
msgToSend = "";
}
String received;
byte[] tabReceived = new byte[256];
dp = new DatagramPacket(tabReceived, tabReceived.length);
System.out.println("Datagram created");
ds.receive(dp);
System.out.println("Datagram received");
received = new String(dp.getData(), 0, dp.getLength());
System.out.println("Received TCP port number: " + received);
int portTCP = Integer.parseInt(received);
int portNumber = (int)((Math.random()*100)+5000);
boolean portAvailable = true;
ServerSocket ss = null;
while(portAvailable) {
try{
ss = new ServerSocket(portNumber);
portAvailable = false;
} catch(Exception e) {
portAvailable = true;
portNumber++;
}
}
System.out.println("ServerSocket created");
Socket s = new Socket(ip, portTCP);
System.out.println("Socket created");
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
out.println("Succes of communication");
String msgFromServer = in.readLine();
System.out.println("Message from SERVER: " + msgFromServer);
in.close();
out.close();
s.close();
ss.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Client(args);
}
}
我认为这里造成问题的是 HashMap 上的同步,但是当我在没有同步的情况下运行它时,数据包以完全随机的顺序出现,没有正确存储在 HashMap 中 - 情况更糟。
如果您有任何建议和建议,我将不胜感激。
【问题讨论】: