I see a problem (Java 6 on SLES11) where a UDP packet is sent back to the client machine (and tcpdump on the client machine shows that it has been received), but the packet is not viewed by Java.
The test works as follows:
The client side generates some random data, inserts it into a UDP packet, sends it to the server on a specific port and expects it to be recalled (with SO_TIMEOUT 180,000 ms). When he receives it back, he prints out that he received it and how long it was sent.
The server side is listening on the UDP packet on this port. When he receives it, he delays the bit, and then sends it back, unchanged. The delay starts at some initial value (3000 ms), and then doubles each time it receives a packet until it reaches a maximum (90,000 ms), after which the delay will simply remain maximum.
It works fine until the delay reaches 48000 ms. The tcpdump operation performed on the client shows the packet being sent and shows the response packet arriving after 48,000 ms. However, the Java program never sees this response packet and, after 180,000 ms, claims to receive timeout. Despite the fact that the client machine received the packet after 48000 ms, as tcpdump shows.
What can happen?
Below is the output of the programs and tcpdump and after that it is the source of the client and server programs.
On the client machine, the output of the test program:
rich-ova3:~/UDPTest2
tcpdump output on client machine (with my comments):
16:03:42.438252 IP 172.16.20.113.16362 > 172.16.20.115.20000: UDP, length 333 16:03:45.439322 IP 172.16.20.115.20000 > 172.16.20.113.16362: UDP, length 333 (a 3011 ms delay) 16:03:45.440315 IP 172.16.20.113.25559 > 172.16.20.115.20000: UDP, length 333 16:03:51.441394 IP 172.16.20.115.20000 > 172.16.20.113.25559: UDP, length 333 (a 6001 ms delay) 16:03:51.441938 IP 172.16.20.113.30457 > 172.16.20.115.20000: UDP, length 333 16:04:03.442564 IP 172.16.20.115.20000 > 172.16.20.113.30457: UDP, length 333 (a 12000 ms delay) 16:04:03.443095 IP 172.16.20.113.46143 > 172.16.20.115.20000: UDP, length 333 16:04:27.443572 IP 172.16.20.115.20000 > 172.16.20.113.46143: UDP, length 333 (a 24001ms delay) 16:04:27.444109 IP 172.16.20.113.31747 > 172.16.20.115.20000: UDP, length 333 16:05:15.444688 IP 172.16.20.115.20000 > 172.16.20.113.31747: UDP, length 333 (a 48001 ms delay) 16:07:27.540689 IP 172.16.20.113.38357 > 172.16.20.115.20000: UDP, length 333 16:08:57.541312 IP 172.16.20.115.20000 > 172.16.20.113.38357: UDP, length 333 (a 90000 ms delay) 16:10:27.627411 IP 172.16.20.113.33915 > 172.16.20.115.20000: UDP, length 333 16:11:57.631436 IP 172.16.20.115.20000 > 172.16.20.113.33915: UDP, length 333 (a 90004 ms delay) 16:13:27.720668 IP 172.16.20.113.36494 > 172.16.20.115.20000: UDP, length 333 16:14:57.722353 IP 172.16.20.115.20000 > 172.16.20.113.36494: UDP, length 333 (a 90001 ms delay)
On the machine, the server output the test program:
rich-ova5:~/UDPTest2
And here is the source client :
import java.io.FileInputStream; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Properties; import java.util.Random; public class Client { private static final String CONFIG_FILE = "client.conf"; private int datagramLength; private boolean debug; private InetAddress server; private int serverPort; private int timeout; private int loops; public static void main(String[] arg) throws Exception { Client c = new Client(); c.go(); } private void go() throws Exception { readClientConfig(); Random rand = new Random(System.currentTimeMillis()); System.out.println("UDP socket timeout is " + timeout + " ms"); byte[] referenceData = new byte[datagramLength]; byte[] sentData = new byte[referenceData.length]; int receiveErrors = 0; int receiveSuccess = 0; int sendErrors = 0; int sendSuccess = 0; for (int i = 0; i < loops; i++) { long sendTime = 0; long receiveTime = 0; rand.nextBytes(referenceData); System.arraycopy(referenceData, 0, sentData, 0, referenceData.length); DatagramSocket serverSock = new DatagramSocket(); serverSock.setSoTimeout(timeout); DatagramPacket datagram = new DatagramPacket(sentData, sentData.length, server, serverPort); try { System.out.println("Sending packet " + (i + 1) + " of " + loops); serverSock.send(datagram); sendSuccess++; } catch (Exception e) { System.out.println("Error sending: " + e.getMessage()); e.printStackTrace(); sendErrors++; continue; } sendTime = System.currentTimeMillis(); try { serverSock.receive(datagram); System.out.println("Received packet " + (i + 1) + " of " + loops); receiveSuccess++; } catch (Exception e) { receiveErrors++; System.out.println("Error receiving: " + e.getMessage()); e.printStackTrace(); } serverSock.close(); receiveTime = System.currentTimeMillis(); System.out.println("Round-trip time: " + (receiveTime - sendTime) + " ms"); byte[] receivedData = datagram.getData(); if (receivedData.length != referenceData.length) { System.out.println("Mismatched packet length."); sendErrors++; } for (int j = 0; j < datagramLength; j++) { if (referenceData[j] != receivedData[j]) { System.out.println("Mismatched packet contents."); sendErrors++; } } System.out.println(); } System.out.println("Send successes: " + sendSuccess); System.out.println("Send errors: " + sendErrors); System.out.println(); System.out.println("Receive successes: " + receiveSuccess); System.out.println("Receive errors: " + receiveErrors); } private void readClientConfig() throws IOException { boolean hasError = false; String val; Properties prop = new Properties(); FileInputStream fis = new FileInputStream(CONFIG_FILE); prop.load(fis); val = prop.getProperty("Server"); if (val == null) { System.out.println("Error reading 'Server': missing value"); hasError = true; } else { try { server = InetAddress.getByName(val); } catch (UnknownHostException e) { System.out.println("Error reading 'Server': " + e.getMessage()); hasError = true; } } val = prop.getProperty("ServerPort", "3000"); try { serverPort = Integer.parseInt(val); } catch (NumberFormatException e) { System.out.println("Error reading 'ServerPort': " + e.getMessage()); hasError = true; } val = prop.getProperty("DatagramLength", "200"); try { datagramLength = Integer.parseInt(val); } catch (NumberFormatException e) { System.out.println("Error reading 'DatagramLength': " + e.getMessage()); hasError = true; }
And source server :
import java.io.FileInputStream; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.util.Properties; public class Server { private static final String CONFIG_FILE = "server.conf"; private int datagramLength; private boolean debug; private int port; private long initialDelay; private long maxDelay; public static void main(String[] arg) throws Exception { Server s = new Server(); s.go(); } private void go() throws Exception { readServerConfig(); DatagramSocket sock = new DatagramSocket(port); sock.setSoTimeout(0); byte[] in = new byte[datagramLength]; DatagramPacket datagram = new DatagramPacket(in, datagramLength);
And client.conf :
# Server address Server = rich-ova5.teak.eng
Finally, server.conf :
# Server port number. Port=20000