我有一个UDP进程需要定义接收端口和IP地址。 经过测试,我发现在请求的同时具有相同的接收IP和端口可能导致数据丢失/切换。 我想到如果现有的请求具有相同的数据,则传入/第二个请求将等待第一个请求完成事务,然后执行请求。 由于这是一个servlet,我同时担心不同浏览器中的多个请求,我使用Semaphore以单例模式返回单个实例。我的DatagramSocket也是单例模式,以避免"已经绑定"错误。 我的代码在一个快乐路径场景中没有数据切换的情况下表现良好,在这种情况下,它只会发送请求和响应而没有错误。 我设置套接字超时并执行超时异常情况,这是我得到的
第一次请求=====> UDP服务器
超时异常< ==== UDP服务器
第二次请求=====> UDP服务器
第一个响应< ==== UDP服务器
我在第二次请求时收到了第一个回复,依此类推。
如何拒绝/跳过超时请求的响应?请注意,我不允许根据要求在我的回复中添加标识符。
这是我的代码供您参考:
private void calludp(String ip, String targetIp, String port, String targetPort, String timeout, byte[] message)
throws IOException, SAXException, ParserConfigurationException, InterruptedException {
String key = targetIp + ":" + targetPort;
UDPReceptionData udpReceptionData = null;
udpReceptionData = getReceptionLock(key, receptionMap);
Semaphore semaphore = udpReceptionData.getSemaphore();
DatagramSocket datagramSocket = udpReceptionData.getDatagramSocket();
semaphore.acquire();
try {
send(ip, targetIp, port, targetPort, timeout, message, datagramSocket);
} finally {
semaphore.release();
}
}
private void populateUDPReceptionMap(String port, String target) {
if ((target != null && !target.isEmpty()) && (port != null && !port.isEmpty())) {
Semaphore semaphore = new Semaphore(1);
DatagramSocket datagramSocket = getSocketMap(port);
UDPReceptionData udpReceptionData = new UDPReceptionData(datagramSocket, semaphore);
this.receptionMap.put(target + ":" + port, udpReceptionData);
}
}
private DatagramSocket getSocketMap(String port) {
System.out.println(socketMap.toString());
DatagramSocket datagramSocket = null;
if (port != null && !port.isEmpty()) {
if (!socketMap.containsKey(port)) {
try {
datagramSocket = new DatagramSocket(Integer.parseInt(port));
this.socketMap.put(port, datagramSocket);
} catch (NumberFormatException | SocketException e) {
e.printStackTrace();
}
} else {
datagramSocket = socketMap.get(port);
}
}
return datagramSocket;
}
public UDPReceptionData getReceptionLock(String ipPort, Map<String, UDPReceptionData> receptionMap) {
System.out.println(receptionMap.toString());
return receptionMap.get(ipPort);
}
public byte[] send(String target, String receptionTarget, String port, String receptionPort, String timeout,
byte[] message, DatagramSocket clientSocket) throws IOException {
String messageResponse = ""; // Message response to be return to the
// caller
int intTimeout = Integer.parseInt(timeout);
DatagramPacket receivePacket = null;
try {
InetAddress ipAddress = InetAddress.getByName(target);
int intPort = Integer.parseInt(port);
byte[] receiveData = new byte[1024];
DatagramPacket sendPacket = new DatagramPacket(message, message.length, ipAddress, intPort);
clientSocket.send(sendPacket);
// receive the data
receivePacket = new DatagramPacket(receiveData, receiveData.length);
try {
clientSocket.setSoTimeout(intTimeout);
clientSocket.receive(receivePacket);
} catch (SocketTimeoutException e) {
throw new SocketTimeoutException("Socket Timeout Exception");
}
messageResponse = new String(receivePacket.getData());
String mes = new String(message, "UTF-8");
System.out.println("FROM SERVER:" + messageResponse + " :::: " + mes);
} finally {
// commented out the close since this is a single instance DatagramSocket
// clientSocket.close();
}
return receivePacket.getData();
}
UDPReceptionData.java
import java.net.DatagramSocket;
import java.util.concurrent.Semaphore;
public class UDPReceptionData {
private Semaphore semaphore;
private DatagramSocket datagramSocket;
public UDPReceptionData(DatagramSocket datagramSocket, Semaphore semaphore) {
this.datagramSocket = datagramSocket;
this.semaphore = semaphore;
}
public DatagramSocket getDatagramSocket() {
return this.datagramSocket;
}
public Semaphore getSemaphore() {
return this.semaphore;
}
}
UDPServer.java
private void udpSender(DatagramSocket serverSocket) throws IOException, InterruptedException {
while (true) {
byte[] responseMessage = new byte[1024];
byte[] requestMessage = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(responseMessage, responseMessage.length);
serverSocket.receive(receivePacket);
String receivedMessage = new String(receivePacket.getData());
System.out.println("RECEIVED: " + receivedMessage);
InetAddress IPAddress = receivePacket.getAddress();
int port = receivePacket.getPort();
requestMessage = receivedMessage.getBytes();
// Set the sending packet to designated IP Address and port
DatagramPacket sendPacket = new DatagramPacket(requestMessage, requestMessage.length, IPAddress, port);
//delay for 4 seconds for timeout testing
Thread.sleep(4000);
serverSocket.send(sendPacket);
}
}
主要方法
public static void main(String[] args) {
UDPProcess m = new UDPProcess();
m.populateUDPReceptionMap("9090", "localhost");
String request = "localhost:9090:message1";
String request2 = "localhost:9090:message2";
new Thread() {
public void run() {
try {
m.calludp("localhost", "localhost", "7979", "9090", "2000", request.getBytes());
} catch (IOException | SAXException | ParserConfigurationException | InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread() {
public void run() {
try {
m.calludp("localhost", "localhost", "7979", "9090", "60000", request2.getBytes());
} catch (IOException | SAXException | ParserConfigurationException | InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
结果:
java.net.SocketTimeoutException: Socket Timeout Exception
at com.comp.proj.connector.UDPProcess.send(UDPProcess.java:221)
at com.comp.proj.connector.UDPProcess.calludp(UDPProcess.java:135)
at com.comp.proj.connector.UDPProcess.access$0(UDPProcess.java:118)
at com.comp.proj.connector.UDPProcess$1.run(UDPProcess.java:51)
FROM SERVER:localhost:9090:message2 :::: localhost:9090:message1
答案 0 :(得分:0)
您的请求和回复中需要序列号。您需要忽略先前序列号的响应。即使没有超时也可能发生这种情况,因为UDP数据报可以复制(或更多)。