HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

"Dealing with Network Timeouts in Java"
Vol. 3, Issue 5, p. 64

Download files assoicated with this article

	

Listing 1.
  
// Timer - thread which counts down to a network timeout,  
//         which prompts a call to timeout() method  
//   
// Written by : David Reilly  
// Last modification date : March 8, 1998  
//  
//  
public class Timer extends Thread  
{  
 // Public consts  
 public static final int REFRESH_RATE = 100;  

 // Private member variables  
 private int m_timeoutValue; // Length of timeout  
 private int m_remainingTime; // Remaining time  
 private boolean m_timeReset;  // time reset  

 // Constructor  
 public Timer ( int milliseconds )  
 {  
  // Assign to member variable  
  m_timeoutValue = milliseconds;  
  m_remainingTime = milliseconds;  
  m_timeReset = false;  
 }  

 public synchronized void resetTimer()  
 {  
  m_remainingTime = m_timeoutValue;  
 }  

 // Thread run method  
 public void run()  
 {  
  // Repeat forever, until program terminates  
  for (;;)  
  {  
   try  
   {  
    // Sleep for the default time refresh rate  
    Thread.sleep(REFRESH_RATE);  

    // Check to see if timer was reset while sleeping  
    if (m_timeReset == true)  
    {  
     // Timer has been reset, so clear our flag  
     m_timeReset = false;  
    }  
    else  
    {  
     // Decrease remaining time  
     m_remainingTime -= REFRESH_RATE;  

     // Has a timeout occured  
     if (m_remainingTime < 0)  
     {  
      // Trigger a timeout  
      timeout();  
     }  
    }  
   }  
   catch (InterruptedException interrupted)  
   {  
    // Disregard - if we are interupted, then  
    // we will simply sleep on the next loop  
   }  
  }  
 }  

 // Override this to provide custom functionality  
 public void timeout()  
 {  
  System.err.println ("Network timeout occured.... terminating");  
  System.exit(1);  
 }  
}  
   

Listing 2.

import java.net.*;  
import java.io.*;  

// MultiThreadedFingerClient  
//   
// Written by : David Reilly  
// Last modification date : March 1, 1998  
//  
// Syntax : hostname username  
//  
//  
public class MultiThreadedFingerClient extends Thread  
{  
 // Public constants  
 public static final int FINGER_PORT = 79; // may need to set this to an ephemeral port  

 // Private member variables  
 private String m_hostname;  
 private String m_username;  
 private Timer m_timer;  

 // Constructor :  
 public MultiThreadedFingerClient(String hostname, String username)  
 {  
  // Assign to member variables  
  m_hostname = hostname;  
  m_username = username;  

  // Five seconds timeout  
  m_timer = new Timer ( 5000 );  
 }  

 // MAIN :  
 public static void main(String args[])  
 {  
  if (args.length != 2)  
  {  
   System.out.println ("MultiThreadedFingerClient hostname user");  
   System.exit(1);  
  }  

  // Create a new   
  new MultiThreadedFingerClient(args[0], args[1]).start();  
 }  

 // connect to server : thread run method  
 public void run()  
 {  
  // Local variables  
  Socket socket = null;  
  int data;  

  // Prompt user  
  System.out.println ("Connecting to " + m_hostname);  

  // Start the timer  
  m_timer.start();  

  try  
  {  
   // Create a socket to the server  
   socket = new Socket ( m_hostname , FINGER_PORT );  

   // Only proceed if connection was established  
   if (socket == null)  
    return;  

   // Get input and output streams to socket  
   BufferedInputStream bufin = new BufferedInputStream( socket.getInputStream() );  
   PrintStream pout = new PrintStream( socket.getOutputStream() ); // deprecated in JDK1.1  
    
   // Print user name  
   pout.println (m_username);  

   // Read in information from server  
   for (;;)  
   {  
    // Read a byte of data  
    data = bufin.read();  

    // Check for end of input stream  
    if (data != -1)  
    {  
     // Cast data to a character and display it  
     System.out.print ( (char) data );  
    }  
    else  
     break; // no more data to be read  

    // Reset our timer  
    m_timer.resetTimer();  
   }  
  }  
  catch (IOException e)  
  {  
   System.err.println ("I/O - " + e);  
  }  

 }  
}  

Listing 3.  

import java.net.*;  
import java.io.*;  

// FingerTimeoutServer  
//   
// Written by : David Reilly  
// Last modification date : March 8, 1998  
//  
//  
public class FingerTimeoutServer extends Thread  
{  
 public static final int FINGER_PORT = 79; // may need to set this to an ephemeral port  

 // Private member vars  
 private Socket m_socket;  

 // Instance count  
 private static int instanceCount = 0;  

 public FingerTimeoutServer ( Socket sock )  
 {  
  // Assign to member variable  
  m_socket = sock;  

  // Increment instanceCount  
  instanceCount++;  
 }  

 public static void main( String args[] )  
 {  
  System.out.println ("Finger Server with simulated timeout");  
    
  try  
  {  
   // Create a server socket, bound to FINGER_PORT  
   ServerSocket serverSocket = new ServerSocket ( FINGER_PORT );  

   // Loop forever, accepting new connecitons  
   for (;;)  
   {  
    Socket sock = serverSocket.accept();  

    // Create an instance of server to process socket  
    FingerTimeoutServer connection = new FingerTimeoutServer ( sock );  
      
    // Start connection thread  
    connection.start();  
   }  
  }  
  catch (IOException ie)  
  {  
   System.err.println ("I/O Error - " + ie);  
   System.exit(0);  
  }  
 }  

 // Main 'work' method  
 public void run()  
 {  
  try  
  {  
   DataInputStream din = new DataInputStream ( m_socket.getInputStream() );  
   PrintStream pout = new PrintStream ( m_socket.getOutputStream() ); // deprecated in JDK1.1  

   // Read a single line of text  
   String username = din.readLine();  

   // Check for presence of user-name.info  
   File userFile = new File ("user-" + username + ".info");  

   // Check if user exists  
   if (userFile.exists())  
   {  
    FileInputStream fin = new FileInputStream( userFile );  

    DataInputStream dfin = new DataInputStream( fin );  

    // Read first line, and send to client  
    String line = dfin.readLine();  
    pout.println (line);  
      
    // Check instance count (if not even, then send data and terminate)  
    if (instanceCount % 2 != 0)  
    {  
     for (;;)  
     {        
      line = dfin.readLine();  

      if (line != null)  
       pout.println (line);  
      else   
       break;  
     }  

     // Close socket  
     m_socket.close();  
    }  
    else  
    {  
     // Simulate timeout by not closing socket  
     pout.println ("Simulating timeout.... if your client doesn't handle timeouts it will stall");  
    }  
   }  
   else  
   {  
    pout.println ("Invalid username");  

    // Close socket  
    m_socket.close();  
   }  
  }  
  catch (IOException ie)  
  {  
   System.out.println ("I/O Error - " + ie);  
  }  
 }  
}  

Listing 4.  

import java.net.*;  
import java.io.*;  

// FingerClient - demonstrates new JDK1.1 networking features  
//   
// Written by : David Reilly  
// Last modification date : March 1, 1998  
//  
// Syntax : hostname username  
//  
//  
public class FingerClient   
{  
 // Public constants  
 public static final int FINGER_PORT = 79; // may need to change to an ephemeral port  

 // Private member variables  
 private String m_hostname;  
 private String m_username;  

 // Constructor :  
 public FingerClient(String hostname, String username)  
 {  
  // Assign to member variables  
  m_hostname = hostname;  
  m_username = username;  

  // Make a connection  
  connect();    
 }  

 // MAIN :  
 public static void main(String args[])  
 {  
  if (args.length != 2)  
  {  
   System.out.println ("FingerClient hostname user");  
   System.exit(1);  
  }  

  new FingerClient(args[0], args[1]);  
 }  

 // connect to server :  
 private void connect()  
 {  
  // Local vars  
  Socket socket = null;  
  int data;  

  // Prompt user  
  System.out.println ("Connecting to " + m_hostname);  

  try  
  {  
   // Create a socket to the server  
   socket = new Socket ( m_hostname , FINGER_PORT );  

   // Only proceed if connection was established  
   if (socket == null)  
    return;  

   // Set SO_TIMEOUT for five seconds  
   socket.setSoTimeout ( 5000 );  

   // Get input and output streams to socket  
   BufferedInputStream bufin = new BufferedInputStream( socket.getInputStream() );  
   PrintStream pout = new PrintStream( socket.getOutputStream() ); // deprecated in JDK1.1  
    
   // Print user name  
   pout.println (m_username);  

   // Read in information from server  
   for (;;)  
   {  
    // Read a byte of data  
    data = bufin.read();  

    // Check for end of input stream  
    if (data != -1)  
    {  
     // Cast data to a character and display it  
     System.out.print ( (char) data );  
    }  
    else  
     break; // no more data to be read  
   }  
  }  
  catch (IOException e)  
  {  
   System.err.println ("I/O - " + e);  
  }  
 }  
}  

Listing 5.  

import java.net.*;  
import java.io.*;  
import java.util.Random;  

// Sender - demonstrates timeouts on a stop-and-wait protocol   
//   
// Written by : David Reilly  
// Last modification date : March 1, 1998  
//  
// Syntax : hostname port  
//  
//  
public class Sender   
{  
 // Priavet member variables  

 // Internet address for receiver  
 private InetAddress m_addr;  

 // Receiver port  
 private int m_port;  

 // Socket to receiver  
 private DatagramSocket m_datagramSocket = null;    

 // Psuedo-random number generator for random sleep interval  
 private Random random;  

 // Default packet size  
 public static final int packetSize = 20;  

 // Constructor for Sender  
 public Sender(String hostname, String port)  
 {  
  // Create a psuedo-random number generator  
  random = new Random();  

  // Obtain an InetAddress object for hostname  
  try  
  {  
   m_addr = InetAddress.getByName ( hostname );  
  }  
  catch (UnknownHostException unknownHost)  
  {  
   System.out.println ("Unknown hostname : " + hostname);  
  }  

  // Convert string into an int  
  try  
  {  
   // Create an integer object and get it's int value  
   m_port = new Integer(port).intValue();  
  }  
  catch (Exception e)  
  {  
   System.out.println ("Invalid port number : " + port);  
   System.exit(1);  
  }  
 }  

 // MAIN method  
 public static void main( String args[] )  
 {  
  if (args.length != 2)  
  {  
   System.out.println ("Sender hostname port");  
   System.exit(1);  
  }  

  // Create an instance of sender  
  Sender sender = new Sender(args[0], args[1]);  

  // Send packets to a receiver  
  sender.transmit();  
 }  

 // Transmit packets to a receiver  
 public void transmit()  
 {    
  // Sequence number  
  int sequenceNumber =0;  

  // Create a datagram socket  
  try  
  {  
   m_datagramSocket = new DatagramSocket();  

   // Set the timeout to two seconds  
   m_datagramSocket.setSoTimeout( 2000 );  
  }  
  catch (SocketException se)  
  {  
   System.err.println ("Error creating a datagram socket - " + se);  
   System.exit(1);  
  }  

    
  for (;;)  
  {  
   // Packets for receiving a response  
   DatagramPacket response = new DatagramPacket(new byte[packetSize], packetSize);  

   try  
   {  
    // Read a packet, and check if its an acknowledgement  
    m_datagramSocket.receive(response);  

    int responseNumber = getSequenceNumber(response);  

    // Does the response ACK match our sequence  
    if (responseNumber == sequenceNumber)  
    {  
     System.out.println ("ACK : " + sequenceNumber);  

     // Increment sequence number  
     sequenceNumber++;  

     System.out.println ("Sending packet " + sequenceNumber);  

     // Send next packet to receiver  
     sendPacket(sequenceNumber, m_addr, m_port);  

    }  
    else  
     System.out.println ("ACK : " + responseNumber + " (expecting" + sequenceNumber + ")");  

    // Sleep for a random length of time... so some timeouts are generated  
    randomSleep();  
   }  
   catch (InterruptedIOException iioe)  
   {  
    // Timeout occured... must resend packet  
    System.out.println ("TIMEOUT : " + sequenceNumber);  

    System.out.println ("Re-sending packet " + sequenceNumber);  

    // Send packet to receiver  
    sendPacket(sequenceNumber, m_addr, m_port);  

   }  
   catch (IOException ioe)  
   {  
    System.out.println ("I/O Error occured - " + ioe);  
   }  
  }  
 }  

 private int getSequenceNumber( DatagramPacket packet )  
 {  
  // Create a byte input stream to read the data  
  ByteArrayInputStream bin = new ByteArrayInputStream (packet.getData());  

  // Create a datainput stream to read sequence number  
  DataInputStream din = new DataInputStream (bin);  

  int sequenceNumber;  

  try  
  {  
   sequenceNumber = din.readInt();  
  }  
  catch (IOException ioe)  
  {  
   sequenceNumber = 0;  
  }  

  return sequenceNumber;  
 }  

 private void sendPacket(int sequenceNumber, InetAddress addr, int port)  
 {  
  try  
  {  
   // Byte array containing response  
   byte[] sendBuffer;  

   // Create output stream to a byte array  
   ByteArrayOutputStream bout = new ByteArrayOutputStream ();  
   DataOutputStream dout = new DataOutputStream (bout);  

   // Write sequence number to packet  
   dout.writeInt(sequenceNumber);  

   // Get data and put in packet  
   sendBuffer = bout.toByteArray();  

   // Create packet for response  
   DatagramPacket response = new DatagramPacket(sendBuffer, sendBuffer.length, addr, port);  
     
   // Send packet through out datagram socket  
   m_datagramSocket.send(response);  
  }  
  catch (IOException ioe)  
  {  
   System.err.println ("Error sending packet - " + ioe);  
  }  
 }  
   

 private void randomSleep()  
 {    
  try  
  {  
   // Generate a random number between five hundred and two thousand five hundred milliseconds  
   int randomValue = (random.nextInt() % 2000) + 500;  
   if (randomValue < 0 ) randomValue = -randomValue;  

   // Sleep for a random length of time  
   Thread.sleep( randomValue );  
  }  
  catch (InterruptedException interrupt)  
  {  
   // Ignore - sleeping is for a random length, so  
   // if we are interrupted that is fine  
  }  
 }  
}  

Listing 6.  

import java.net.*;  
import java.io.*;  

// Receiver - demonstrates timeouts on a stop-and-wait protocol   
//   
// Written by : David Reilly  
// Last modification date : March 1, 1998  
//  
//  
public class Receiver   
{   
 // Private member variables  

 // Internet address of sender  
 private InetAddress m_addr;  
   
 // Port of sender  
 private int m_port;  

 // DatagramSocket to communicate with sender  
 private DatagramSocket m_datagramSocket;  
   
 // Public constants  

 // Default packet size  
 public static final int packetSize = 20;  

 // Port for communication  
 public static final int port = 8000;  

 // Number of re-tries before terminating  
 public static final int maxRetry = 10;  

 // Constructor for receiver  
 public Receiver( )  
 {  
  try  
  {  
   // Create a datagram socket bound to a specific port  
   m_datagramSocket = new DatagramSocket ( port );  
  }  
  catch (IOException e)  
  {  
   System.err.println ("Error binding to socket - " + port);  
   System.exit(1);  
  }  
 }  

 public void receive()  
 {  
  // Local variables  
  int retryCount = 0;  
  int sequenceNumber = 0;  
  boolean messageArrived;  

  // Datagram packet for messages  
  DatagramPacket message = new DatagramPacket ( new byte[packetSize], packetSize);  

  try  
  {  
   // Receive the first message  
   m_datagramSocket.receive(message);  

   // Set a timeout for future communications  
   m_datagramSocket.setSoTimeout ( 5000 );  

   // Use the address and port of this packet's sender  
   m_addr = message.getAddress();  
   m_port = message.getPort();  

   System.out.println ("Packet received from " + m_addr.getHostName() +":" + m_port);  
  }  
  catch (IOException e)  
  {  
   System.err.println ("Error reading packet - " + e);  
   System.exit(1);  
  }  

  // Wait for the first message  
  for (;;)  
  {  
   try  
   {  
    // Every twelfth packet, simulate a delay  
    // This will cause timeouts at sender, and  
    // packets will be re-sent by sender.  
    if ( sequenceNumber % 12 == 0)  
     try  
     {  
      // Sleep for ten seconds  
      Thread.sleep(10000);  
     }  
     catch (InterruptedException e)  
     {  
      // Ignore, as timeout is only for simulation purposes  
     }  

    // Send response  
    sendPacket(sequenceNumber, m_addr, m_port);  

    // Receive messages  
    m_datagramSocket.receive(message);  
   }  
   catch (InterruptedIOException iioe)  
   {  
    // Notify user  
    System.out.println ("TIMEOUT : " + sequenceNumber);  
    continue;  
   }  
   catch (IOException ioe)  
   {  
    // Notify user  
    System.err.println ("IOException -" + ioe);  

    // Terminate  
    System.exit(1);  
   }  

   // Get sequence number of message  
   int packetNumber = getSequenceNumber(message);  
    
   // Is it an older packet  
   if ( packetNumber <  sequenceNumber )  
   {  
    sendPacket ( getSequenceNumber ( message ) , m_addr, m_port );  

    System.out.println ("Old packet (" + getSequenceNumber(message) + ") acknowledged");  
   }  
   else  
   if ( packetNumber > sequenceNumber )  
   {  
    System.out.println ("Future packet (" + getSequenceNumber(message) + ") received... ignoring");  
   }  
   // Packet number matches sequence number  
   else  
   {  
    // Print to screen  
    System.out.println ( "DATA : " + packetNumber );  

    // Increment sequence number  
    sequenceNumber++;  
   }     
  }  
 }  

 // Gets the sequence number from a packet  
 private int getSequenceNumber( DatagramPacket packet )  
 {  
  // Create a byte input stream to read the data  
  ByteArrayInputStream bin = new ByteArrayInputStream (packet.getData());  

  // Create a datainput stream to read sequence number  
  DataInputStream din = new DataInputStream (bin);  

  int sequenceNumber;  

  try  
  {  
   sequenceNumber = din.readInt();  
  }  
  catch (IOException ioe)  
  {  
   sequenceNumber = 0;  
  }  

  return sequenceNumber;  
 }  

 // Sends a packet  
 private void sendPacket(int sequenceNumber, InetAddress addr, int port)  
 {  
  try  
  {  
   // Byte array containing response  
   byte[] sendBuffer;  

   // Create output stream to a byte array  
   ByteArrayOutputStream bout = new ByteArrayOutputStream ();  
   DataOutputStream dout = new DataOutputStream (bout);  

   // Write sequence number to packet  
   dout.writeInt(sequenceNumber);  

   // Get data and put in packet  
   sendBuffer = bout.toByteArray();  

   // Create packet for response  
   DatagramPacket response = new DatagramPacket(sendBuffer, sendBuffer.length, addr, port);  
     
   // Send packet through out datagram socket  
   m_datagramSocket.send(response);  
  }  
  catch (IOException ioe)  
  {  
   System.err.println ("Error sending packet - " + ioe);  
  }  
 }  

 // MAIN method  
 public static void main (String args[])  
 {  
  Receiver receiver = new Receiver();  

  receiver.receive();  
 }  
}
  
      
 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.