Solution for the UDP Lab

The following code presents one solution for the UDP lab. It contains code for the UDPClient.java and UDPPinger.java classes. The other classes do not require modifications in the basic lab.

UDPClient.java

  1. /**
  2. * UDPClient.java -- Simple UDP client
  3. *
  4. * $Id: UDPClient.java,v 1.2 2003/10/14 14:25:30 kangasha Exp $
  5. *
  6. */
  7.  
  8. import java.net.*;
  9. import java.io.*;
  10. import java.util.*;
  11.  
  12. public class UDPClient extends UDPPinger implements Runnable {
  13. /** Host to ping */
  14. String remoteHost;
  15. /** Port number of remote host */
  16. int remotePort;
  17.  
  18. /** How many pings to send */
  19. static final int NUM_PINGS = 10;
  20. /** How many reply pings have we received */
  21. int numReplies = 0;
  22. /** Array for holding replies and RTTs */
  23. static boolean[] replies = new boolean[NUM_PINGS];
  24. static long[] rtt = new long[NUM_PINGS];
  25.  
  26. /* Send our own pings at least once per second. If no replies received
  27. within 5 seconds, assume ping was lost. */
  28. /** 1 second timeout for waiting replies */
  29. static final int TIMEOUT = 1000;
  30. /** 5 second timeout for collecting pings at the end */
  31. static final int REPLY_TIMEOUT = 5000;
  32.  
  33. /** Create UDPClient object. */
  34. public UDPClient(String host, int port) {
  35. remoteHost = host;
  36. remotePort = port;
  37. }
  38.  
  39. /** Main code for pinger client thread. */
  40. public void run() {
  41. /* Create socket. We do not care which local port we use. */
  42. createSocket();
  43. try {
  44. socket.setSoTimeout(TIMEOUT);
  45. } catch (SocketException e) {
  46. System.out.println("Error setting timeout TIMEOUT: " + e);
  47. }
  48.  
  49. for (int i = 0; i < NUM_PINGS; i++) {
  50. /* Message we want to send. Add space at the end for easy
  51. parsing of replies. */
  52. Date now = new Date();
  53. String message = "PING " + i + " " + now.getTime() + " ";
  54. replies[i] = false;
  55. rtt[i] = 1000000;
  56. PingMessage ping = null;
  57.  
  58. /* Send ping to recipient */
  59. try {
  60. ping = new PingMessage(InetAddress.getByName(remoteHost),
  61. remotePort, message);
  62. } catch (UnknownHostException e) {
  63. System.out.println("Cannot find host: " + e);
  64. }
  65. sendPing(ping);
  66.  
  67. /* Read reply */
  68. try {
  69. PingMessage reply = receivePing();
  70. handleReply(reply.getContents());
  71. } catch (SocketTimeoutException e) {
  72. /* Reply did not arrive. Do nothing for now. Figure
  73. * out lost pings later. */
  74. }
  75. }
  76. /* We sent all our pings. Now check if there are still missing
  77. replies. Wait for a reply, if nothing comes, then assume it
  78. was lost. If a reply arrives, keep looking until nothing comes
  79. within a reasonable timeout. */
  80. try {
  81. socket.setSoTimeout(REPLY_TIMEOUT);
  82. } catch (SocketException e) {
  83. System.out.println("Error setting timeout REPLY_TIMEOUT: " + e);
  84. }
  85. while (numReplies < NUM_PINGS) {
  86. try {
  87. PingMessage reply = receivePing();
  88. handleReply(reply.getContents());
  89. } catch (SocketTimeoutException e) {
  90. /* Nothing coming our way apparently. Exit loop. */
  91. numReplies = NUM_PINGS;
  92. }
  93. }
  94. /* Print statistics */
  95. for (int i = 0; i < NUM_PINGS; i++) {
  96. System.out.println("PING " + i + ": " + replies[i] +
  97. " RTT: " + rtt[i]);
  98. }
  99.  
  100. }
  101.  
  102. /** Handle the incoming ping message. For now, just count it as
  103. * having been correctly received. */
  104. private void handleReply(String reply) {
  105. String[] tmp = reply.split(" ");
  106. int pingNumber = Integer.parseInt(tmp[1]);
  107. long then = Long.parseLong(tmp[2]);
  108. replies[pingNumber] = true;
  109. /* Calculate RTT and store it in the rtt-array. */
  110. Date now = new Date();
  111. rtt[pingNumber] = now.getTime() - then;
  112. numReplies++;
  113. }
  114.  
  115. /** Main function. Read command line arguments and start the
  116. * client thread. */
  117. public static void main(String args[]) {
  118. String host = null;
  119. int port = 0;
  120.  
  121. /* Parse host and port number from commandline */
  122. try {
  123. host = args[0];
  124. port = Integer.parseInt(args[1]);
  125. } catch (ArrayIndexOutOfBoundsException e) {
  126. System.out.println("Need two arguments: remoteHost remotePort");
  127. System.exit(-1);
  128. } catch (NumberFormatException e) {
  129. System.out.println("Please give port number as integer.");
  130. System.exit(-1);
  131. }
  132. System.out.println("Contacting host " + host + " at port " + port);
  133.  
  134. UDPClient Client = new UDPClient(host, port);
  135. Client.run();
  136. }
  137. }

UDPPinger.java

  1. /**
  2. * UDPPinger.java -- Basic routines for UDP pinger
  3. *
  4. * $Id: UDPPinger.java,v 1.1.1.1 2003/09/30 14:36:11 kangasha Exp $
  5. *
  6. */
  7.  
  8. import java.net.*;
  9. import java.io.*;
  10. import java.util.*;
  11.  
  12. public class UDPPinger {
  13. /** Socket which we use. */
  14. DatagramSocket socket;
  15.  
  16. /** Maximum length of a PING message. */
  17. static final int MAX_PING_LEN = 1024;
  18.  
  19. /** Create a socket for sending UDP messages */
  20. public void createSocket() {
  21. try {
  22. socket = new DatagramSocket();
  23. } catch (SocketException e) {
  24. System.out.println("Error creating socket: " + e);
  25. }
  26. }
  27.  
  28. /** Create a socket for receiving UDP messages. This socket must be
  29. * bound to the given port. */
  30. public void createSocket(int port) {
  31. try {
  32. socket = new DatagramSocket(port);
  33. } catch (SocketException e) {
  34. System.out.println("Error creating socket: " + e);
  35. }
  36. }
  37.  
  38. /** Send a UDP ping message which is given as the argument. */
  39. public void sendPing(PingMessage ping) {
  40. InetAddress host = ping.getHost();
  41. int port = ping.getPort();
  42. String message = ping.getContents();
  43.  
  44. try {
  45. /* Create a datagram packet addressed to the recipient */
  46. DatagramPacket packet =
  47. new DatagramPacket(message.getBytes(), message.length(),
  48. host, port);
  49.  
  50. /* Send the packet */
  51. socket.send(packet);
  52. System.out.println("Sent message to " + host + ":" + port);
  53. } catch (IOException e) {
  54. System.out.println("Error sending packet: " + e);
  55. }
  56. }
  57.  
  58. /** Receive a UDP ping message and return the received message. We
  59. throw an exception to indicate that the socket timed out. This
  60. can happen when a message was lost in the network. */
  61. public PingMessage receivePing() throws SocketTimeoutException {
  62. /* Create packet for receiving the reply */
  63. byte recvBuf[] = new byte[MAX_PING_LEN];
  64. DatagramPacket recvPacket =
  65. new DatagramPacket(recvBuf, MAX_PING_LEN);
  66. PingMessage reply = null;
  67.  
  68. /* Read message from socket. */
  69. try {
  70. socket.receive(recvPacket);
  71.  
  72. System.out.println("Received message from " +
  73. recvPacket.getAddress() +
  74. ":" + recvPacket.getPort());
  75. String recvMsg = new String(recvPacket.getData());
  76. reply = new PingMessage(recvPacket.getAddress(),
  77. recvPacket.getPort(),
  78. recvMsg);
  79.  
  80. } catch (SocketTimeoutException e) {
  81. /* Note: Because the socket has a timeout, we may get a
  82. * SocketTimeoutException. The calling function needs to
  83. * know of this timeout to know when to quit. However,
  84. * SocketTimeoutException is a subclass of IOException
  85. * which signals read errors on the socket, so we need to
  86. * catch SocketTimeoutException here and throw it
  87. * forward. */
  88. throw e;
  89. } catch (IOException e) {
  90. System.out.println("Error reading from socket: " + e);
  91. }
  92. return reply;
  93. }
  94. }