Java/Network Protocol/Server

Материал из Java эксперт
Перейти к: навигация, поиск

A generic framework for a flexible, multi-threaded server

   <source lang="java">

/*

* Copyright (c) 2000 David Flanagan.  All rights reserved.
* This code is from the book Java Examples in a Nutshell, 2nd Edition.
* It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
* You may study, use, and modify it for any non-commercial purpose.
* You may distribute it non-commercially as long as you retain this notice.
* For a commercial use license, or to purchase the book (recommended),
* visit http://www.davidflanagan.ru/javaexamples2.
*/

import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.InterruptedIOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; /**

* This class is a generic framework for a flexible, multi-threaded server. It
* listens on any number of specified ports, and, when it receives a connection
* on a port, passes input and output streams to a specified Service object
* which provides the actual service. It can limit the number of concurrent
* connections, and logs activity to a specified stream.
*/

public class Server {

 /**
  * A main() method for running the server as a standalone program. The
  * command-line arguments to the program should be pairs of servicenames and
  * port numbers. For each pair, the program will dynamically load the named
  * Service class, instantiate it, and tell the server to provide that
  * Service on the specified port. The special -control argument should be
  * followed by a password and port, and will start special server control
  * service running on the specified port, protected by the specified
  * password.
  */
 public static void main(String[] args) {
   try {
     if (args.length < 2) // Check number of arguments
       throw new IllegalArgumentException("Must specify a service");
     // Create a Server object that uses standard out as its log and
     // has a limit of ten concurrent connections at once.
     Server s = new Server(System.out, 10);
     // Parse the argument list
     int i = 0;
     while (i < args.length) {
       if (args[i].equals("-control")) { // Handle the -control arg
         i++;
         String password = args[i++];
         int port = Integer.parseInt(args[i++]);
         // add control service
         s.addService(new Control(s, password), port);
       } else {
         // Otherwise start a named service on the specified port.
         // Dynamically load and instantiate a Service class
         String serviceName = args[i++];
         Class serviceClass = Class.forName(serviceName);
         Service service = (Service) serviceClass.newInstance();
         int port = Integer.parseInt(args[i++]);
         s.addService(service, port);
       }
     }
   } catch (Exception e) { // Display a message if anything goes wrong
     System.err.println("Server: " + e);
     System.err.println("Usage: java Server "
         + "[-control <password> <port>] "
         + "[<servicename> <port> ... ]");
     System.exit(1);
   }
 }
 // This is the state for the server
 Map services; // Hashtable mapping ports to Listeners
 Set connections; // The set of current connections
 int maxConnections; // The concurrent connection limit
 ThreadGroup threadGroup; // The threadgroup for all our threads
 PrintWriter logStream; // Where we send our logging output to
 /**
  * This is the Server() constructor. It must be passed a stream to send log
  * output to (may be null), and the limit on the number of concurrent
  * connections.
  */
 public Server(OutputStream logStream, int maxConnections) {
   setLogStream(logStream);
   log("Starting server");
   threadGroup = new ThreadGroup(Server.class.getName());
   this.maxConnections = maxConnections;
   services = new HashMap();
   connections = new HashSet(maxConnections);
 }
 /**
  * A public method to set the current logging stream. Pass null to turn
  * logging off
  */
 public synchronized void setLogStream(OutputStream out) {
   if (out != null)
     logStream = new PrintWriter(out);
   else
     logStream = null;
 }
 /** Write the specified string to the log */
 protected synchronized void log(String s) {
   if (logStream != null) {
     logStream.println("[" + new Date() + "] " + s);
     logStream.flush();
   }
 }
 /** Write the specified object to the log */
 protected void log(Object o) {
   log(o.toString());
 }
 /**
  * This method makes the server start providing a new service. It runs the
  * specified Service object on the specified port.
  */
 public synchronized void addService(Service service, int port)
     throws IOException {
   Integer key = new Integer(port); // the hashtable key
   // Check whether a service is already on that port
   if (services.get(key) != null)
     throw new IllegalArgumentException("Port " + port
         + " already in use.");
   // Create a Listener object to listen for connections on the port
   Listener listener = new Listener(threadGroup, port, service);
   // Store it in the hashtable
   services.put(key, listener);
   // Log it
   log("Starting service " + service.getClass().getName() + " on port "
       + port);
   // Start the listener running.
   listener.start();
 }
 /**
  * This method makes the server stop providing a service on a port. It does
  * not terminate any pending connections to that service, merely causes the
  * server to stop accepting new connections
  */
 public synchronized void removeService(int port) {
   Integer key = new Integer(port); // hashtable key
   // Look up the Listener object for the port in the hashtable
   final Listener listener = (Listener) services.get(key);
   if (listener == null)
     return;
   // Ask the listener to stop
   listener.pleaseStop();
   // Remove it from the hashtable
   services.remove(key);
   // And log it.
   log("Stopping service " + listener.service.getClass().getName()
       + " on port " + port);
 }
 /**
  * This nested Thread subclass is a "listener". It listens for connections
  * on a specified port (using a ServerSocket) and when it gets a connection
  * request, it calls the servers addConnection() method to accept (or
  * reject) the connection. There is one Listener for each Service being
  * provided by the Server.
  */
 public class Listener extends Thread {
   ServerSocket listen_socket; // The socket to listen for connections
   int port; // The port we"re listening on
   Service service; // The service to provide on that port
   volatile boolean stop = false; // Whether we"ve been asked to stop
   /**
    * The Listener constructor creates a thread for itself in the
    * threadgroup. It creates a ServerSocket to listen for connections on
    * the specified port. It arranges for the ServerSocket to be
    * interruptible, so that services can be removed from the server.
    */
   public Listener(ThreadGroup group, int port, Service service)
       throws IOException {
     super(group, "Listener:" + port);
     listen_socket = new ServerSocket(port);
     // give it a non-zero timeout so accept() can be interrupted
     listen_socket.setSoTimeout(600000);
     this.port = port;
     this.service = service;
   }
   /***********************************************************************
    * This is the polite way to get a Listener to stop accepting
    * connections
    **********************************************************************/
   public void pleaseStop() {
     this.stop = true; // Set the stop flag
     this.interrupt(); // Stop blocking in accept()
     try {
       listen_socket.close();
     } // Stop listening.
     catch (IOException e) {
     }
   }
   /**
    * A Listener is a Thread, and this is its body. Wait for connection
    * requests, accept them, and pass the socket on to the addConnection
    * method of the server.
    */
   public void run() {
     while (!stop) { // loop until we"re asked to stop.
       try {
         Socket client = listen_socket.accept();
         addConnection(client, service);
       } catch (InterruptedIOException e) {
       } catch (IOException e) {
         log(e);
       }
     }
   }
 }
 /**
  * This is the method that Listener objects call when they accept a
  * connection from a client. It either creates a Connection object for the
  * connection and adds it to the list of current connections, or, if the
  * limit on connections has been reached, it closes the connection.
  */
 protected synchronized void addConnection(Socket s, Service service) {
   // If the connection limit has been reached
   if (connections.size() >= maxConnections) {
     try {
       // Then tell the client it is being rejected.
       PrintWriter out = new PrintWriter(s.getOutputStream());
       out.print("Connection refused; "
           + "the server is busy; please try again later.\n");
       out.flush();
       // And close the connection to the rejected client.
       s.close();
       // And log it, of course
       log("Connection refused to "
           + s.getInetAddress().getHostAddress() + ":"
           + s.getPort() + ": max connections reached.");
     } catch (IOException e) {
       log(e);
     }
   } else { // Otherwise, if the limit has not been reached
     // Create a Connection thread to handle this connection
     Connection c = new Connection(s, service);
     // Add it to the list of current connections
     connections.add(c);
     // Log this new connection
     log("Connected to " + s.getInetAddress().getHostAddress() + ":"
         + s.getPort() + " on port " + s.getLocalPort()
         + " for service " + service.getClass().getName());
     // And start the Connection thread to provide the service
     c.start();
   }
 }
 /**
  * A Connection thread calls this method just before it exits. It removes
  * the specified Connection from the set of connections.
  */
 protected synchronized void endConnection(Connection c) {
   connections.remove(c);
   log("Connection to " + c.client.getInetAddress().getHostAddress() + ":"
       + c.client.getPort() + " closed.");
 }
 /** Change the current connection limit */
 public synchronized void setMaxConnections(int max) {
   maxConnections = max;
 }
 /**
  * This method displays status information about the server on the specified
  * stream. It can be used for debugging, and is used by the Control service
  * later in this example.
  */
 public synchronized void displayStatus(PrintWriter out) {
   // Display a list of all Services that are being provided
   Iterator keys = services.keySet().iterator();
   while (keys.hasNext()) {
     Integer port = (Integer) keys.next();
     Listener listener = (Listener) services.get(port);
     out.print("SERVICE " + listener.service.getClass().getName()
         + " ON PORT " + port + "\n");
   }
   // Display the current connection limit
   out.print("MAX CONNECTIONS: " + maxConnections + "\n");
   // Display a list of all current connections
   Iterator conns = connections.iterator();
   while (conns.hasNext()) {
     Connection c = (Connection) conns.next();
     out.print("CONNECTED TO "
         + c.client.getInetAddress().getHostAddress() + ":"
         + c.client.getPort() + " ON PORT "
         + c.client.getLocalPort() + " FOR SERVICE "
         + c.service.getClass().getName() + "\n");
   }
 }
 /**
  * This class is a subclass of Thread that handles an individual connection
  * between a client and a Service provided by this server. Because each such
  * connection has a thread of its own, each Service can have multiple
  * connections pending at once. Despite all the other threads in use, this
  * is the key feature that makes this a multi-threaded server
  * implementation.
  */
 public class Connection extends Thread {
   Socket client; // The socket to talk to the client through
   Service service; // The service being provided to that client
   /**
    * This constructor just saves some state and calls the superclass
    * constructor to create a thread to handle the connection. Connection
    * objects are created by Listener threads. These threads are part of
    * the server"s ThreadGroup, so all Connection threads are part of that
    * group, too.
    */
   public Connection(Socket client, Service service) {
     super("Server.Connection:"
         + client.getInetAddress().getHostAddress() + ":"
         + client.getPort());
     this.client = client;
     this.service = service;
   }
   /**
    * This is the body of each and every Connection thread. All it does is
    * pass the client input and output streams to the serve() method of the
    * specified Service object. That method is responsible for reading from
    * and writing to those streams to provide the actual service. Recall
    * that the Service object has been passed from the Server.addService()
    * method to a Listener object to the addConnection() method to this
    * Connection object, and is now finally being used to provide the
    * service. Note that just before this thread exits it always calls the
    * endConnection() method to remove itself from the set of connections
    */
   public void run() {
     try {
       InputStream in = client.getInputStream();
       OutputStream out = client.getOutputStream();
       service.serve(in, out);
     } catch (IOException e) {
       log(e);
     } finally {
       endConnection(this);
     }
   }
 }
 /**
  * Here is the Service interface that we have seen so much of. It defines
  * only a single method which is invoked to provide the service. serve()
  * will be passed an input stream and an output stream to the client. It
  * should do whatever it wants with them, and should close them before
  * returning.
  * 
  * All connections through the same port to this service share a single
  * Service object. Thus, any state local to an individual connection must be
  * stored in local variables within the serve() method. State that should be
  * global to all connections on the same port should be stored in instance
  * variables of the Service class. If the same Service is running on more
  * than one port, there will typically be different Service instances for
  * each port. Data that should be global to all connections on any port
  * should be stored in static variables.
  * 
  * Note that implementations of this interface must have a no-argument
  * constructor if they are to be dynamically instantiated by the main()
  * method of the Server class.
  */
 public interface Service {
   public void serve(InputStream in, OutputStream out) throws IOException;
 }
 /**
  * A very simple service. It displays the current time on the server to the
  * client, and closes the connection.
  */
 public static class Time implements Service {
   public void serve(InputStream i, OutputStream o) throws IOException {
     PrintWriter out = new PrintWriter(o);
     out.print(new Date() + "\n");
     out.close();
     i.close();
   }
 }
 /**
  * This is another example service. It reads lines of input from the client,
  * and sends them back, reversed. It also displays a welcome message and
  * instructions, and closes the connection when the user enters a "." on a
  * line by itself.
  */
 public static class Reverse implements Service {
   public void serve(InputStream i, OutputStream o) throws IOException {
     BufferedReader in = new BufferedReader(new InputStreamReader(i));
     PrintWriter out = new PrintWriter(new BufferedWriter(
         new OutputStreamWriter(o)));
     out.print("Welcome to the line reversal server.\n");
     out.print("Enter lines.  End with a "." on a line by itself.\n");
     for (;;) {
       out.print("> ");
       out.flush();
       String line = in.readLine();
       if ((line == null) || line.equals("."))
         break;
       for (int j = line.length() - 1; j >= 0; j--)
         out.print(line.charAt(j));
       out.print("\n");
     }
     out.close();
     in.close();
   }
 }
 /**
  * This service is an HTTP mirror, just like the HttpMirror class
  * implemented earlier in this chapter. It echos back the client"s HTTP
  * request
  */
 public static class HTTPMirror implements Service {
   public void serve(InputStream i, OutputStream o) throws IOException {
     BufferedReader in = new BufferedReader(new InputStreamReader(i));
     PrintWriter out = new PrintWriter(o);
     out.print("HTTP/1.0 200 \n");
     out.print("Content-Type: text/plain\n\n");
     String line;
     while ((line = in.readLine()) != null) {
       if (line.length() == 0)
         break;
       out.print(line + "\n");
     }
     out.close();
     in.close();
   }
 }
 /**
  * This service demonstrates how to maintain state across connections by
  * saving it in instance variables and using synchronized access to those
  * variables. It maintains a count of how many clients have connected and
  * tells each client what number it is
  */
 public static class UniqueID implements Service {
   public int id = 0;
   public synchronized int nextId() {
     return id++;
   }
   public void serve(InputStream i, OutputStream o) throws IOException {
     PrintWriter out = new PrintWriter(o);
     out.print("You are client #: " + nextId() + "\n");
     out.close();
     i.close();
   }
 }
 /**
  * This is a non-trivial service. It implements a command-based protocol
  * that gives password-protected runtime control over the operation of the
  * server. See the main() method of the Server class to see how this service
  * is started.
  * 
  * The recognized commands are: password: give password; authorization is
  * required for most commands add: dynamically add a named service on a
  * specified port remove: dynamically remove the service running on a
  * specified port max: change the current maximum connection limit. status:
  * display current services, connections, and connection limit help: display
  * a help message quit: disconnect
  * 
  * This service displays a prompt, and sends all of its output to the user
  * in capital letters. Only one client is allowed to connect to this service
  * at a time.
  */
 public static class Control implements Service {
   Server server; // The server we control
   String password; // The password we require
   boolean connected = false; // Whether a client is already connected
   /**
    * Create a new Control service. It will control the specified Server
    * object, and will require the specified password for authorization
    * Note that this Service does not have a no argument constructor, which
    * means that it cannot be dynamically instantiated and added as the
    * other, generic services above can be.
    */
   public Control(Server server, String password) {
     this.server = server;
     this.password = password;
   }
   /**
    * This is the serve method that provides the service. It reads a line
    * the client, and uses java.util.StringTokenizer to parse it into
    * commands and arguments. It does various things depending on the
    * command.
    */
   public void serve(InputStream i, OutputStream o) throws IOException {
     // Setup the streams
     BufferedReader in = new BufferedReader(new InputStreamReader(i));
     PrintWriter out = new PrintWriter(o);
     String line; // For reading client input lines
     // Has the user has given the password yet?
     boolean authorized = false;
     // If there is already a client connected to this service, display
     // a message to this client and close the connection. We use a
     // synchronized block to prevent a race condition.
     synchronized (this) {
       if (connected) {
         out.print("ONLY ONE CONTROL CONNECTION ALLOWED.\n");
         out.close();
         return;
       } else
         connected = true;
     }
     // This is the main loop: read a command, parse it, and handle it
     for (;;) { // infinite loop
       out.print("> "); // Display a prompt
       out.flush(); // Make it appear right away
       line = in.readLine(); // Get the user"s input
       if (line == null)
         break; // Quit if we get EOF.
       try {
         // Use a StringTokenizer to parse the user"s command
         StringTokenizer t = new StringTokenizer(line);
         if (!t.hasMoreTokens())
           continue; // if input was empty
         // Get first word of the input and convert to lower case
         String command = t.nextToken().toLowerCase();
         // Now compare to each of the possible commands, doing the
         // appropriate thing for each command
         if (command.equals("password")) { // Password command
           String p = t.nextToken(); // Get the next word
           if (p.equals(this.password)) { // Is it the password?
             out.print("OK\n"); // Say so
             authorized = true; // Grant authorization
           } else
             out.print("INVALID PASSWORD\n"); // Otherwise fail
         } else if (command.equals("add")) { // Add Service command
           // Check whether password has been given
           if (!authorized)
             out.print("PASSWORD REQUIRED\n");
           else {
             // Get the name of the service and try to
             // dynamically load and instantiate it.
             // Exceptions will be handled below
             String serviceName = t.nextToken();
             Class serviceClass = Class.forName(serviceName);
             Service service;
             try {
               service = (Service) serviceClass.newInstance();
             } catch (NoSuchMethodError e) {
               throw new IllegalArgumentException(
                   "Service must have a "
                       + "no-argument constructor");
             }
             int port = Integer.parseInt(t.nextToken());
             // If no exceptions occurred, add the service
             server.addService(service, port);
             out.print("SERVICE ADDED\n"); // acknowledge
           }
         } else if (command.equals("remove")) { // Remove service
           if (!authorized)
             out.print("PASSWORD REQUIRED\n");
           else {
             int port = Integer.parseInt(t.nextToken());
             server.removeService(port); // remove the service
             out.print("SERVICE REMOVED\n"); // acknowledge
           }
         } else if (command.equals("max")) { // Set connection limit
           if (!authorized)
             out.print("PASSWORD REQUIRED\n");
           else {
             int max = Integer.parseInt(t.nextToken());
             server.setMaxConnections(max);
             out.print("MAX CONNECTIONS CHANGED\n");
           }
         } else if (command.equals("status")) { // Status Display
           if (!authorized)
             out.print("PASSWORD REQUIRED\n");
           else
             server.displayStatus(out);
         } else if (command.equals("help")) { // Help command
           // Display command syntax. Password not required
           out.print("COMMANDS:\n" + "\tpassword <password>\n"
               + "\tadd <service> <port>\n"
               + "\tremove <port>\n"
               + "\tmax <max-connections>\n" + "\tstatus\n"
               + "\thelp\n" + "\tquit\n");
         } else if (command.equals("quit"))
           break; // Quit command.
         else
           out.print("UNRECOGNIZED COMMAND\n"); // Error
       } catch (Exception e) {
         out.print("ERROR WHILE PARSING OR EXECUTING COMMAND:\n" + e
             + "\n");
       }
     }
     connected = false;
     out.close();
     in.close();
   }
 }

}


 </source>
   
  
 
  



A multithreaded server

   <source lang="java">

import java.io.IOException; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; public class MultiThreadServer implements Runnable {

 Socket csocket;
 MultiThreadServer(Socket csocket) {
   this.csocket = csocket;
 }
 public static void main(String args[]) throws Exception {
   ServerSocket ssock = new ServerSocket(1234);
   System.out.println("Listening");
   while (true) {
     Socket sock = ssock.accept();
     System.out.println("Connected");
     new Thread(new MultiThreadServer(sock)).start();
   }
 }
 public void run() {
   try {
     PrintStream pstream = new PrintStream(csocket.getOutputStream());
     for (int i = 100; i >= 0; i--) {
       pstream.println(i + " bottles of beer on the wall");
     }
     pstream.close();
     csocket.close();
   } catch (IOException e) {
     System.out.println(e);
   }
 }

}


 </source>
   
  
 
  



A server can use specialized streams to deliver typed data

   <source lang="java">

import java.io.DataInputStream; import java.io.DataOutputStream; import java.net.ServerSocket; import java.net.Socket; public class DataServer {

 public static void main(String args[]) throws Exception {
   ServerSocket ssock = new ServerSocket(1234);
   while (true) {
     System.out.println("Listening");
     Socket sock = ssock.accept();
     DataOutputStream dstream = new DataOutputStream(sock
         .getOutputStream());
     dstream.writeFloat(3.14159265f);
     dstream.close();
     sock.close();
   }
 }

} class DataClient {

 public static void main(String[] args) throws Exception {
   Socket sock = new Socket(args[0], 1234);
   DataInputStream dis = new DataInputStream(sock.getInputStream());
   float f = dis.readFloat();
   System.out.println("PI=" + f);
   dis.close();
   sock.close();
 }

}


 </source>
   
  
 
  



Base class to build multithreaded servers easily

   <source lang="java">

import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; class MTServerBase extends Thread {

 protected Socket socket;
 public void run() {
   try {
     String s = "Server.";
     socket.getOutputStream().write(s.getBytes());
     socket.close();
   } catch (Exception e) {
     System.out.println(e);
   }
 }
 static public void startServer(int port, Class clobj) {
   ServerSocket ssock;
   Socket sock;
   try {
     ssock = new ServerSocket(port);
     while (true) {
       Socket esock = null;
       try {
         esock = ssock.accept();
         MTServerBase t = (MTServerBase) clobj.newInstance();
         t.socket = esock;
         t.start();
       } catch (Exception e) {
         try {
           esock.close();
         } catch (Exception ec) {
         }
       }
     }
   } catch (IOException e) {
   }
 }

} public class UCServer extends MTServerBase {

 public void run() {
   try {
     InputStream is = socket.getInputStream();
     OutputStream os = socket.getOutputStream();
     while (true) {
       char c = (char) is.read();
       // end on Control+C or Control+D
       if (c == "\003" || c == "\004")
         break;
       os.write(Character.toUpperCase(c));
     }
     socket.close();
   } catch (Exception e) {
     System.out.println(e);
   }
 }
 public static void main(String[] args) {
   int n = Integer.parseInt(args[0]);
   System.out.println("Starting server on port " + n);
   startServer(n, UCServer.class);
 }

}


 </source>
   
  
 
  



Client and Server Demo

   <source lang="java">

/* From http://java.sun.ru/docs/books/tutorial/index.html */ /*

* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
*  list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
*  this list of conditions and the following disclaimer in the documentation
*  and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; public class EchoClient {

   public static void main(String[] args) throws IOException {
       Socket echoSocket = null;
       PrintWriter out = null;
       BufferedReader in = null;
       try {
           echoSocket = new Socket("taranis", 7);
           out = new PrintWriter(echoSocket.getOutputStream(), true);
           in = new BufferedReader(new InputStreamReader(
                                       echoSocket.getInputStream()));
       } catch (UnknownHostException e) {
           System.err.println("Don"t know about host: taranis.");
           System.exit(1);
       } catch (IOException e) {
           System.err.println("Couldn"t get I/O for "
                              + "the connection to: taranis.");
           System.exit(1);
       }
 BufferedReader stdIn = new BufferedReader(
                                  new InputStreamReader(System.in));
 String userInput;
 while ((userInput = stdIn.readLine()) != null) {
     out.println(userInput);
     System.out.println("echo: " + in.readLine());
 }
 out.close();
 in.close();
 stdIn.close();
 echoSocket.close();
   }

} ////////////////////////////////////////////////////////////

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class KnockKnockServer {

 public static void main(String[] args) throws IOException {
   ServerSocket serverSocket = null;
   try {
     serverSocket = new ServerSocket(4444);
   } catch (IOException e) {
     System.err.println("Could not listen on port: 4444.");
     System.exit(1);
   }
   Socket clientSocket = null;
   try {
     clientSocket = serverSocket.accept();
   } catch (IOException e) {
     System.err.println("Accept failed.");
     System.exit(1);
   }
   PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
   BufferedReader in = new BufferedReader(new InputStreamReader(
       clientSocket.getInputStream()));
   String inputLine, outputLine;
   KnockKnockProtocol kkp = new KnockKnockProtocol();
   outputLine = kkp.processInput(null);
   out.println(outputLine);
   while ((inputLine = in.readLine()) != null) {
     outputLine = kkp.processInput(inputLine);
     out.println(outputLine);
     if (outputLine.equals("Bye."))
       break;
   }
   out.close();
   in.close();
   clientSocket.close();
   serverSocket.close();
 }

} class KnockKnockProtocol {

 private static final int WAITING = 0;
 private static final int SENTKNOCKKNOCK = 1;
 private static final int SENTCLUE = 2;
 private static final int ANOTHER = 3;
 private static final int NUMJOKES = 5;
 private int state = WAITING;
 private int currentJoke = 0;
 private String[] clues = { "Turnip", "Little Old Lady", "Atch", "Who",
     "Who" };
 private String[] answers = { "Turnip the heat, it"s cold in here!",
     "I didn"t know you could yodel!", "Bless you!",
     "Is there an owl in here?", "Is there an echo in here?" };
 public String processInput(String theInput) {
   String theOutput = null;
   if (state == WAITING) {
     theOutput = "Knock! Knock!";
     state = SENTKNOCKKNOCK;
   } else if (state == SENTKNOCKKNOCK) {
     if (theInput.equalsIgnoreCase("Who"s there?")) {
       theOutput = clues[currentJoke];
       state = SENTCLUE;
     } else {
       theOutput = "You"re supposed to say \"Who"s there?\"! "
           + "Try again. Knock! Knock!";
     }
   } else if (state == SENTCLUE) {
     if (theInput.equalsIgnoreCase(clues[currentJoke] + " who?")) {
       theOutput = answers[currentJoke] + " Want another? (y/n)";
       state = ANOTHER;
     } else {
       theOutput = "You"re supposed to say \"" + clues[currentJoke]
           + " who?\"" + "! Try again. Knock! Knock!";
       state = SENTKNOCKKNOCK;
     }
   } else if (state == ANOTHER) {
     if (theInput.equalsIgnoreCase("y")) {
       theOutput = "Knock! Knock!";
       if (currentJoke == (NUMJOKES - 1))
         currentJoke = 0;
       else
         currentJoke++;
       state = SENTKNOCKKNOCK;
     } else {
       theOutput = "Bye.";
       state = WAITING;
     }
   }
   return theOutput;
 }

} ////////////////////////////////////////////////////////////

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class KKMultiServer {

 public static void main(String[] args) throws IOException {
   ServerSocket serverSocket = null;
   boolean listening = true;
   try {
     serverSocket = new ServerSocket(4444);
   } catch (IOException e) {
     System.err.println("Could not listen on port: 4444.");
     System.exit(-1);
   }
   while (listening)
     new KKMultiServerThread(serverSocket.accept()).start();
   serverSocket.close();
 }

} class KKMultiServerThread extends Thread {

 private Socket socket = null;
 public KKMultiServerThread(Socket socket) {
   super("KKMultiServerThread");
   this.socket = socket;
 }
 public void run() {
   try {
     PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
     BufferedReader in = new BufferedReader(new InputStreamReader(socket
         .getInputStream()));
     String inputLine, outputLine;
     KnockKnockProtocol kkp = new KnockKnockProtocol();
     outputLine = kkp.processInput(null);
     out.println(outputLine);
     while ((inputLine = in.readLine()) != null) {
       outputLine = kkp.processInput(inputLine);
       out.println(outputLine);
       if (outputLine.equals("Bye"))
         break;
     }
     out.close();
     in.close();
     socket.close();
   } catch (IOException e) {
     e.printStackTrace();
   }
 }

} class KnockKnockProtocol {

 private static final int WAITING = 0;
 private static final int SENTKNOCKKNOCK = 1;
 private static final int SENTCLUE = 2;
 private static final int ANOTHER = 3;
 private static final int NUMJOKES = 5;
 private int state = WAITING;
 private int currentJoke = 0;
 private String[] clues = { "Turnip", "Little Old Lady", "Atch", "Who",
     "Who" };
 private String[] answers = { "Turnip the heat, it"s cold in here!",
     "I didn"t know you could yodel!", "Bless you!",
     "Is there an owl in here?", "Is there an echo in here?" };
 public String processInput(String theInput) {
   String theOutput = null;
   if (state == WAITING) {
     theOutput = "Knock! Knock!";
     state = SENTKNOCKKNOCK;
   } else if (state == SENTKNOCKKNOCK) {
     if (theInput.equalsIgnoreCase("Who"s there?")) {
       theOutput = clues[currentJoke];
       state = SENTCLUE;
     } else {
       theOutput = "You"re supposed to say \"Who"s there?\"! "
           + "Try again. Knock! Knock!";
     }
   } else if (state == SENTCLUE) {
     if (theInput.equalsIgnoreCase(clues[currentJoke] + " who?")) {
       theOutput = answers[currentJoke] + " Want another? (y/n)";
       state = ANOTHER;
     } else {
       theOutput = "You"re supposed to say \"" + clues[currentJoke]
           + " who?\"" + "! Try again. Knock! Knock!";
       state = SENTKNOCKKNOCK;
     }
   } else if (state == ANOTHER) {
     if (theInput.equalsIgnoreCase("y")) {
       theOutput = "Knock! Knock!";
       if (currentJoke == (NUMJOKES - 1))
         currentJoke = 0;
       else
         currentJoke++;
       state = SENTKNOCKKNOCK;
     } else {
       theOutput = "Bye.";
       state = WAITING;
     }
   }
   return theOutput;
 }

} ////////////////////////////////////////////////////////////

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; public class KnockKnockClient {

 public static void main(String[] args) throws IOException {
   Socket kkSocket = null;
   PrintWriter out = null;
   BufferedReader in = null;
   try {
     kkSocket = new Socket("taranis", 4444);
     out = new PrintWriter(kkSocket.getOutputStream(), true);
     in = new BufferedReader(new InputStreamReader(kkSocket
         .getInputStream()));
   } catch (UnknownHostException e) {
     System.err.println("Don"t know about host: taranis.");
     System.exit(1);
   } catch (IOException e) {
     System.err
         .println("Couldn"t get I/O for the connection to: taranis.");
     System.exit(1);
   }
   BufferedReader stdIn = new BufferedReader(new InputStreamReader(
       System.in));
   String fromServer;
   String fromUser;
   while ((fromServer = in.readLine()) != null) {
     System.out.println("Server: " + fromServer);
     if (fromServer.equals("Bye."))
       break;
     fromUser = stdIn.readLine();
     if (fromUser != null) {
       System.out.println("Client: " + fromUser);
       out.println(fromUser);
     }
   }
   out.close();
   in.close();
   stdIn.close();
   kkSocket.close();
 }

}


 </source>
   
  
 
  



Client estimates the speed of the network connection to the server

   <source lang="java">

import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.util.Calendar; public class UdpEchoClient {

 static final String testString = "Greeks bearing gifts";
 public static void main(String[] args) {
   InetAddress address;
   try {
     address = InetAddress.getByName(args[0]);
   } catch (UnknownHostException host) {
     System.out.println(host);
     return;
   }
   DatagramPacket pack = new DatagramPacket(testString.getBytes(),
       testString.length(), address, 7);
   DatagramPacket incoming = new DatagramPacket(new byte[256], 256);
   DatagramSocket sock = null;
   try {
     Calendar start, end;
     sock = new DatagramSocket();
     start = Calendar.getInstance();
     sock.send(pack);
     sock.setSoTimeout(5000);
     sock.receive(incoming);
     end = Calendar.getInstance();
     String reply = new String(incoming.getData());
     reply = reply.substring(0, testString.length());
     if (reply.equals(testString)) {
       System.out.println("Success");
       System.out.println("Time = "
           + (end.getTime().getTime() - start.getTime().getTime())
           + "mS");
     } else
       System.out.println("Reply data did not match");
   } catch (SocketException socke) {
     System.out.println(socke);
   } catch (IOException ioe) {
     System.out.println(ioe);
   } finally {
     sock.close();
   }
 }

}


 </source>
   
  
 
  



Logging Server based on SocketServer

   <source lang="java">

import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; public class Main {

 public static void main(String args[]) throws Exception {
   ServerSocket serverSocket = new ServerSocket(8080);
   Socket socket = serverSocket.accept();
   InputStream inStream = socket.getInputStream();
   BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
   String str = null;
   while ((str = reader.readLine()) != null) {
     System.out.println(str);
   }
 }

}

 </source>
   
  
 
  



Manage a pool of threads for clients

   <source lang="java">

import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class PoolServerBase extends Thread {

 protected Socket socket;
 static PoolServerBase head = null;
 protected PoolServerBase next = null;
 static protected boolean init(Class clobj, int threads) {
   try {
     for (int i = 0; i < threads; i++) {
       PoolServerBase thread = (PoolServerBase) clobj.newInstance();
       thread.next = head;
       head = thread;
       thread.start();
     }
   } catch (Exception e) {
     return false;
   }
   return true;
 }
 static synchronized protected void addToList(PoolServerBase me) {
   me.next = head;
   head = me;
 }
 synchronized protected void waitForSignal() {
   try {
     wait();
   } catch (InterruptedException e) {
   }
 }
 public void run() {
   while (true) {
     waitForSignal();
     doClientProcessing();
     addToList(this);
   }
 }
 synchronized protected void handleClient(Socket s) {
   socket = s;
   notify();
 }
 protected void doClientProcessing() {
   try {
     String s = "Server.";
     s += "Thread: " + this.toString();
     socket.getOutputStream().write(s.getBytes());
     sleep(10000); // simulate processing
     s = "Complete";
     socket.getOutputStream().write(s.getBytes());
     socket.close();
   } catch (Exception e) {
     System.out.println(e);
   }
 }
 static synchronized protected boolean listEmpty() {
   return head == null;
 }
 static protected void assignThread(Socket sock) {
   PoolServerBase t = head;
   head = head.next;
   t.socket = sock;
   synchronized (t) {
     t.notify();
   }
 }
 static public void startServer(int port) {
   ServerSocket ssock;
   Socket sock;
   try {
     ssock = new ServerSocket(port);
     while (true) {
       Socket esock = null;
       try {
         esock = ssock.accept();
         while (listEmpty())
           yield();
         assignThread(esock);
       } catch (Exception e) {
         try {
           esock.close();
         } catch (Exception ec) {
         }
       }
     }
   } catch (IOException e) {
   }
 }
 static public void main(String args[]) {
   init(PoolServerBase.class, 3);
   System.out.println("Starting server on port 808");
   startServer(808);
 }

}


 </source>
   
  
 
  



Quote Server

   <source lang="java">

/* From http://java.sun.ru/docs/books/tutorial/index.html */ /*

* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
*  list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
*  this list of conditions and the following disclaimer in the documentation
*  and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/

import java.io.DataInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.util.Date; public class QuoteServer {

 public static void main(String[] args) throws IOException {
   new QuoteServerThread().start();
 }

} class QuoteServerThread extends Thread {

 private DatagramSocket socket = null;
 private DataInputStream in = null;
 private boolean moreQuotes = true;
 public QuoteServerThread() throws IOException {
   super("QuoteServerThread");
   socket = new DatagramSocket(4445);
   try {
     in = new DataInputStream(new FileInputStream("one-liners.txt"));
   } catch (FileNotFoundException e) {
     System.err
         .println("Could not open quote file. Serving time instead.");
   }
 }
 public void run() {
   while (moreQuotes) {
     try {
       byte[] buf = new byte[256];
       // receive request
       DatagramPacket packet = new DatagramPacket(buf, buf.length);
       socket.receive(packet);
       // figure out response
       String dString = null;
       if (in == null)
         dString = new Date().toString();
       else
         dString = getNextQuote();
       dString.getBytes(0, dString.length(), buf, 0);
       // send the response to the client at "address" and "port"
       InetAddress address = packet.getAddress();
       int port = packet.getPort();
       packet = new DatagramPacket(buf, buf.length, address, port);
       socket.send(packet);
     } catch (IOException e) {
       e.printStackTrace();
       moreQuotes = false;
     }
   }
   socket.close();
 }
 private String getNextQuote() {
   String returnValue = null;
   try {
     if ((returnValue = in.readLine()) == null) {
       in.close();
       moreQuotes = false;
       returnValue = "No more quotes. Goodbye.";
     }
   } catch (IOException e) {
     returnValue = "IOException occurred in server.";
   }
   return returnValue;
 }

} ///////////////////////////////////////////////// import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class QuoteClient {

 public static void main(String[] args) throws IOException {
   if (args.length != 1) {
     System.out.println("Usage: java QuoteClient <hostname>");
     return;
   }
   // get a datagram socket
   DatagramSocket socket = new DatagramSocket();
   // send request
   byte[] buf = new byte[256];
   InetAddress address = InetAddress.getByName(args[0]);
   DatagramPacket packet = new DatagramPacket(buf, buf.length, address,
       4445);
   socket.send(packet);
   // get response
   packet = new DatagramPacket(buf, buf.length);
   socket.receive(packet);
   // display response
   String received = new String(packet.getData());
   System.out.println("Quote of the Moment: " + received);
   socket.close();
 }

} /////////////////////////////////////////////////


 </source>
   
  
 
  



Reflector

   <source lang="java">

import java.io.BufferedReader; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.MulticastSocket; import java.net.UnknownHostException; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; import java.util.StringTokenizer; import java.util.Vector; public class Reflector implements Runnable {

 // valid names found in the config file:
 public static final String MODE = "Mode";
 public static final String SOURCE_IP = "SourceIP";
 public static final String SOURCE_PORT = "SourcePort";
 public static final String DEST_IP = "DestIP";
 public static final String DEST_PORT = "DestPort";
 // valid modes in the config file, unicast to
 // multicast or multicast to unicast
 public static final String INPUT_UNITOMULTI = "UNI_TO_MULTI";
 public static final String INPUT_MULTITOUNI = "MULTI_TO_UNI";
 // possible modes the reflector can be set to:
 public static final int MODE_NONE = 0;
 public static final int MODE_UNI_TO_MULTI = 1;
 public static final int MODE_MULTI_TO_UNI = 2;
 // variables to indicate source or destination
 public static final int SOURCE = 1;
 public static final int DEST = 2;
 // min and max network ports allowed
 public static final int MIN_PORT = 1024;
 public static final int MAX_PORT = 65095;
 // which mode the reflector is being run in:
 private int mode = 0;
 // source and destination hold variables:
 private Address source;
 private Hashtable dest;
 private Address hold_dest = null;
 // logging toggle and logger class
 boolean logging = true;
 Logger logger;
 public Reflector() {
 }
 public void run() {
   // validate the config file
   if (readConfig() != 0) {
     System.err.println("Error parsing config file\n");
     System.exit(-1);
   }
   // start the logger
   logger = new Logger(logging);
   // spawn a thread to listen for packets
   ReflectorListener listener = new ReflectorListener(source, mode, logger);
   System.out.println("Listening on " + source.toString());
   // spawn threads for each source address packets
   // are to be forwarded on. Register each thread as
   // PacketListenerInterface with the listener thread.
   System.out.println("Sending on:");
   for (Enumeration e = dest.elements(); e.hasMoreElements();) {
     Address a = (Address) e.nextElement();
     ReflectorSender sender = new ReflectorSender(a, mode, logger);
     sender.start();
     listener.addPacketListener((PacketListenerInterface) sender);
     System.out.println("           " + a.toString());
   }
   // start the listener
   listener.start();
 }
 public int readConfig() {
   // validate the contents of the config file
   BufferedReader input = null;
   String name, value, inputLine = null;
   dest = new Hashtable();
   // open and read the config file
   try {
     input = new BufferedReader(new FileReader("reflector.conf"));
     inputLine = input.readLine();
   } catch (IOException e) {
     System.err.println("Error reading reflector.conf.");
     return (-1);
   }
   // loop until entire config file is read
   while (inputLine != null) {
     // skip comments:
     if (inputLine.charAt(0) != "#") {
       // extract a name/value pair, and branch
       // based on the name:
       StringTokenizer tokenizer = new StringTokenizer(inputLine, "=");
       name = tokenizer.nextToken();
       value = tokenizer.nextToken();
       if (name == null) {
         System.out.println("no name");
         continue;
       } else if (name.equals(MODE)) {
         if (setMode(value) != 0) {
           System.err.println("Error setting mode to " + value);
           return (-1);
         }
       } else if (name.equals(SOURCE_IP)) {
         if (setSourceIP(value) != 0) {
           System.err.println("Error setting src IP address to "
               + value);
           return (-1);
         }
       } else if (name.equals(SOURCE_PORT)) {
         if (setSourcePort(value) != 0) {
           System.err
               .println("Error setting src port to " + value);
           return (-1);
         }
       } else if (name.equals(DEST_IP)) {
         if (setDestIP(value) != 0) {
           System.err.println("Error setting dest IP address to "
               + value);
           return (-1);
         }
       } else if (name.equals(DEST_PORT)) {
         if (setDestPort(value) != 0) {
           System.err.println("Error setting dest port to "
               + value);
           return (-1);
         }
       } else {
         System.err.println("Skipping invalid config file value: "
             + name);
       }
     }
     // read next line in the config file
     try {
       inputLine = input.readLine();
     } catch (IOException e) {
       System.err.println("Error reading reflector.conf.");
       return (-1);
     }
   }
   // close the config file
   try {
     input.close();
   } catch (IOException e) {
     System.err.println("Error closing reflector.conf.");
     return (-1);
   }
   // validate that the combined contents of the config file
   // make sense
   if (!isConfigValid()) {
     System.err.println("Configuration file is not complete.");
     return (-1);
   }
   return (0);
 }
 private int setMode(String value) {
   // validate and set the mode from the config file
   if (value.equals(INPUT_UNITOMULTI)) {
     mode = MODE_UNI_TO_MULTI;
     return (0);
   } else if (value.equals(INPUT_MULTITOUNI)) {
     mode = MODE_MULTI_TO_UNI;
     return (0);
   } else {
     return (-1);
   }
 }
 private int setSourceIP(String value) {
   // validate and set the source IP from the config file
   // call modeToAddress to validate IP address
   InetAddress inet = modeToAddress(value, SOURCE);
   if (inet == null)
     return -1;
   if (source != null) {
     if (source.getAddress() != null)
       System.err.println("Warning: overwriting src address "
           + source.getAddress().getHostAddress() + " with "
           + inet.getHostAddress() + ".");
     source.setAddress(inet);
   } else {
     source = new Address(inet);
   }
   return (0);
 }
 private int setSourcePort(String value) {
   // validate and set the source port from the config file
   int port;
   try {
     port = Integer.parseInt(value);
   } catch (NumberFormatException nfe) {
     return (-1);
   }
   if ((port < MIN_PORT) || (port > 65095))
     return (-1);
   if (source != null) {
     if (source.getPort() != 0)
       System.err.println("Warning: overwriting src port "
           + source.getPort() + " with port " + port + ".");
     source.setPort(port);
   } else {
     source = new Address(port);
   }
   return (0);
 }
 private int setDestIP(String value) {
   // validate and set the dest IP from the config file
   // call modeToAddress to validate IP address
   InetAddress inet = modeToAddress(value, DEST);
   if (inet == null)
     return -1;
   if (hold_dest != null) {
     if (hold_dest.getAddress() != null)
       System.err.println("Warning: overwriting dest address "
           + hold_dest.getAddress().getHostAddress() + " with "
           + inet.getHostAddress() + ".");
     hold_dest.setAddress(inet);
     if (hold_dest.isComplete())
       return (addDest());
   } else {
     hold_dest = new Address(inet);
   }
   return (0);
 }
 private int setDestPort(String value) {
   // validate and set the dest port from the config file
   int port;
   try {
     port = Integer.parseInt(value);
   } catch (NumberFormatException nfe) {
     return (-1);
   }
   if ((port < MIN_PORT) || (port > MAX_PORT))
     return (-1);
   if (hold_dest != null) {
     if (hold_dest.getPort() != 0)
       System.err.println("Warning: overwriting dest port "
           + hold_dest.getPort() + " with port " + port + ".");
     hold_dest.setPort(port);
     if (hold_dest.isComplete())
       return (addDest());
   } else {
     hold_dest = new Address(port);
   }
   return (0);
 }
 private int addDest() {
   // once both a dest IP and port have been read, add them
   // to our vector of all destinations.
   switch (mode) {
   case MODE_UNI_TO_MULTI:
     if (!dest.isEmpty()) {
       System.err.println("Warning: dest address overwritten");
       dest.clear();
     }
     dest.put(hold_dest.toString(), hold_dest);
     break;
   case MODE_MULTI_TO_UNI:
     dest.put(hold_dest.toString(), hold_dest);
     break;
   default:
     // no mode set
     System.err.println("Destination " + hold_dest.toString()
         + " skipped because no mode set.");
     hold_dest = null;
     return (-1);
   }
   hold_dest = null;
   return (0);
 }
 private InetAddress modeToAddress(String value, int type) {
   // validate the IP Address based on its text value, its
   // type (DEST or SOURCE), and the mode (UNI_TO_MULTI or
   // MULTI_TO_UNI). Returns an InetAddress if succesfull and
   // null on failure.
   InetAddress inet;
   if ((type != DEST) && (type != SOURCE)) {
     System.err.println("Invalid type passed to modeToAddress (" + type
         + ")");
     return (null);
   }
   switch (mode) {
   case MODE_UNI_TO_MULTI:
     if (type == DEST)
       inet = returnValidMCIP(value);
     else
       inet = returnValidIP(value);
     break;
   case MODE_MULTI_TO_UNI:
     if (type == DEST)
       inet = returnValidIP(value);
     else
       inet = returnValidMCIP(value);
     break;
   default:
     // no mode set
     System.err.println("Error: No Mode Selected.");
     return (null);
   }
   if (inet == null)
     System.err.println("Invalid dest IP address (" + value + ").");
   return (inet);
 }
 private InetAddress returnValidIP(String IP) {
   // return InetAddress if IP is valid, null otherwise
   InetAddress inet;
   try {
     inet = InetAddress.getByName(IP);
   } catch (UnknownHostException e) {
     return (null);
   }
   return (inet);
 }
 private InetAddress returnValidMCIP(String IP) {
   // return InetAddress if IP is valid multicast addr,
   // null otherwise
   InetAddress inet = returnValidIP(IP);
   if (inet.isMulticastAddress()) {
     return (inet);
   } else {
     return (null);
   }
 }
 public boolean isConfigValid() {
   // validate that the mode, source IP/port, and
   // dest IP(s)/port(s) are all valid and a valid
   // combination.
   if (mode == MODE_NONE) {
     System.err.println("No mode selected.");
     return (false);
   }
   if (!source.isComplete()) {
     if ((source.getPort() != 0) && (mode == MODE_UNI_TO_MULTI)) {
       // if source is unicast local IP is implied
       try {
         source.setAddress(InetAddress.getLocalHost());
       } catch (UnknownHostException e) {
         System.err.println("Incomplete source address.");
         return (false);
       }
     } else {
       System.err.println("Incomplete source address.");
       return (false);
     }
   }
   if (dest.isEmpty()) {
     System.err.println("No destination addresses.");
     return (false);
   }
   for (Enumeration e = dest.elements(); e.hasMoreElements();) {
     Address a = (Address) e.nextElement();
     if (!a.isComplete()) {
       System.err.println("Incompete destination address.");
       return (false);
     }
   }
   return (true);
 }
 public static void main(String args[]) {
   Reflector r = new Reflector();
   r.run();
 }

} //Address class is used to store an IP address and port //combination. class Address {

 private InetAddress address = null;
 private int port = 0;
 public Address(InetAddress address, int port) {
   this.address = address;
   this.port = port;
 }
 public Address(InetAddress address) {
   this.address = address;
 }
 public Address(int port) {
   this.port = port;
 }
 public InetAddress getAddress() {
   return (address);
 }
 public int getPort() {
   return (port);
 }
 public void setPort(int port) {
   this.port = port;
 }
 public void setAddress(InetAddress address) {
   this.address = address;
 }
 public boolean isComplete() {
   // return true if both IP and port are populated,
   // false otherwise.
   if ((address != null) && (port != 0))
     return (true);
   else
     return (false);
 }
 public String toString() {
   // return a string representation of the IP/port.
   String str;
   if (address == null)
     str = "";
   else
     str = address.getHostAddress();
   str = str + "/" + port;
   return (str);
 }

} //Logger class opens and writes to the log file //if boolean true is passed as constructor argument. class Logger {

 private boolean logging;
 private FileWriter logfile;
 public Logger(boolean logging) {
   this.logging = logging;
   if (logging) {
     try {
       // open logfile for append
       logfile = new FileWriter("reflector.log", true);
     } catch (IOException e) {
       System.err.println("Error opening log file.");
     }
     log("Reflector started: " + new Date());
   }
 }
 public void log(String str) {
   // write string to logfile
   // if logging disabled return
   if (!logging)
     return;
   try {
     logfile.write(str + "\n");
     logfile.flush();
   } catch (IOException e) {
     System.err.println("Error writing to log file.");
   }
 }

} //ReflectorSender creates a unicast or multicast socket //and is registered to receive incoming packet notifications //via the PacketListenerInterface. Incoming packets //are forwarded on the outgoing socket. class ReflectorSender extends Thread implements PacketListenerInterface {

 private InetAddress sendAddr;
 private int sendPort;
 private int mode;
 private DatagramSocket ds = null;
 private Logger logger;
 public ReflectorSender(Address a, int mode, Logger logger) {
   sendAddr = a.getAddress();
   sendPort = a.getPort();
   this.mode = mode;
   this.logger = logger;
 }
 public void run() {
   // initialize a DatagramSocket or MulticastSocket
   // based on the mode:
   switch (mode) {
   case Reflector.MODE_MULTI_TO_UNI:
     ds = initUnicastSocket();
     break;
   case Reflector.MODE_UNI_TO_MULTI:
     ds = (DatagramSocket) initMulticastSocket();
     break;
   default:
     break;
   }
 }
 private MulticastSocket initMulticastSocket() {
   // initialize a MulticastSocket
   MulticastSocket mc;
   try {
     mc = new MulticastSocket(sendPort);
   } catch (Exception e) {
     e.printStackTrace();
     return (null);
   }
   return (mc);
 }
 private DatagramSocket initUnicastSocket() {
   // initialize a DatagramSocket
   DatagramSocket ds;
   try {
     ds = new DatagramSocket(sendPort);
   } catch (Exception e) {
     e.printStackTrace();
     return (null);
   }
   return (ds);
 }
 public void packetReceived(DatagramPacket packet) {
   // An incoming packet has been received. Override
   // the old packet addressing to the new outgoing
   // addressing, send it and log it.
   try {
     packet.setAddress(sendAddr);
     packet.setPort(sendPort);
     ds.send(packet);
     logger.log("Packet forwarded to "
         + packet.getAddress().getHostAddress() + "/"
         + packet.getPort() + ", " + packet.getLength() + " bytes");
   } catch (IOException e) {
     System.err.println("Error sending packet");
     e.printStackTrace();
   }
 }

} //ReflectorListener thread listens for packets //and notifies one or more interested threads //who register as PacketListenerInterfaces. class ReflectorListener extends Thread {

 private InetAddress listenAddr;
 private int listenPort;
 private int mode;
 private Vector packetListeners;
 private Logger logger;
 private static final int MAX_PACKET_SIZE = 1500;
 public ReflectorListener(Address a, int mode, Logger logger) {
   listenAddr = a.getAddress();
   listenPort = a.getPort();
   this.mode = mode;
   this.logger = logger;
   packetListeners = new Vector();
 }
 public void run() {
   // create a unicast or multicast socket
   // depending on the mode and listen for packets.
   switch (mode) {
   case Reflector.MODE_UNI_TO_MULTI:
     DatagramSocket ds = initUnicastSocket();
     if (ds != null)
       listen(ds);
     break;
   case Reflector.MODE_MULTI_TO_UNI:
     MulticastSocket mc = initMulticastSocket();
     if (mc != null)
       listen((DatagramSocket) mc);
     break;
   default:
     break;
   }
 }
 private MulticastSocket initMulticastSocket() {
   // initialize a MulticastSocket and join the group
   MulticastSocket mc;
   try {
     mc = new MulticastSocket(listenPort);
     mc.joinGroup(listenAddr);
   } catch (Exception e) {
     System.err.println("Failed to create MulticastSocket on " + "port "
         + listenPort);
     return (null);
   }
   return (mc);
 }
 private DatagramSocket initUnicastSocket() {
   // initialize a DatagramSocket
   DatagramSocket ds;
   try {
     ds = new DatagramSocket(listenPort);
   } catch (Exception e) {
     System.err.println("Failed to create DatagramSocket on " + "port "
         + listenPort);
     return (null);
   }
   return (ds);
 }
 private void listen(DatagramSocket ds) {
   // loop forever listening to packets, when they
   // arrive log them and notify all interested threads.
   byte[] buffer;
   DatagramPacket packet;
   while (true) {
     try {
       buffer = new byte[MAX_PACKET_SIZE];
       packet = new DatagramPacket(buffer, buffer.length);
       ds.receive(packet);
       logger.log("Packet received, " + packet.getLength() + " bytes");
       eventNotify(packet);
     } catch (IOException e) {
       System.err.println("Error receiving packet\n");
       e.printStackTrace();
     }
   }
 }
 public void addPacketListener(PacketListenerInterface pl) {
   // add interested thread to listeners vector
   packetListeners.addElement(pl);
 }
 public void removePacketListener(PacketListenerInterface pl) {
   // remove thread to listeners vector
   packetListeners.removeElement(pl);
 }
 private void eventNotify(DatagramPacket packet) {
   // notify all registered threads that a packet has arrived
   // using the packetReceived(DatagramPacket) method.
   for (Enumeration e = packetListeners.elements(); e.hasMoreElements();) {
     PacketListenerInterface pl = (PacketListenerInterface) e
         .nextElement();
     pl.packetReceived(packet);
   }
 }

} //PacketListenerInterface used by threads that need to //be notified of datagram packet receipt. A single //interface function packetReceived passes the packet //information to the thread requiring the information. interface PacketListenerInterface {

 public void packetReceived(DatagramPacket packet);

}


 </source>
   
  
 
  



Serve entire objects using ObjectOutputStream

   <source lang="java">

import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Hashtable; public class ObjServer {

 public static void main(String args[]) throws Exception {
   ServerSocket ssock = new ServerSocket(1234);
   Hashtable hash = new Hashtable();
   hash.put("Java Source and Support", "www.jexp.ru");
   while (true) {
     System.out.println("Listening");
     Socket sock = ssock.accept();
     ObjectOutputStream ostream = new ObjectOutputStream(sock
         .getOutputStream());
     ostream.writeObject(hash);
     ostream.close();
     sock.close();
   }
 }

} // A Java-specific client can read objects from Java servers. class ObjClient {

 public static void main(String[] args) throws Exception {
   Socket sock = new Socket(args[0], 1234);
   ObjectInputStream ois = new ObjectInputStream(sock.getInputStream());
   Hashtable hash = (Hashtable) ois.readObject();
   System.out.println(hash);
   ois.close();
   sock.close();
 }

}


 </source>
   
  
 
  



Server allows connections on socket 6123

   <source lang="java">

import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; public class SocketDemo {

 public static void main(String[] args) {
   try {
     ServerSocket server = new ServerSocket(6123);
     while (true) {
       System.out.println("Listening");
       Socket sock = server.accept();
       InetAddress addr = sock.getInetAddress();
       System.out.println("Connection made to " + addr.getHostName()
           + " (" + addr.getHostAddress() + ")");
       pause(5000);
       sock.close();
     }
   } catch (IOException e) {
     System.out.println("Exception detected: " + e);
   }
 }
 private static void pause(int ms) {
   try {
     Thread.sleep(ms);
   } catch (InterruptedException e) {
   }
 }

}


 </source>
   
  
 
  



The client can specify information to control the output of a server

   <source lang="java">

import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; public class AnotherBeerServer {

 public static void main(String args[]) throws Exception {
   ServerSocket ssock = new ServerSocket(1234);
   System.out.println("Listening");
   Socket sock = ssock.accept();
   ssock.close(); // no more connects
   PrintStream ps = new PrintStream(sock.getOutputStream());
   // ask for count
   ps.print("count? ");
   BufferedReader input = new BufferedReader(new InputStreamReader(sock
       .getInputStream()));
   // read and parse it
   String line = input.readLine();
   ps.println("");
   int count = Integer.parseInt(line);
   for (int i = count; i >= 0; i--) {
     ps.println(i + " Java Source and Support.");
   }
   ps.close();
   sock.close();
 }

}


 </source>
   
  
 
  



This server displays messages to a single client

   <source lang="java">

import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; public class BeerServer {

 public static void main(String args[]) throws Exception {
   ServerSocket ssock = new ServerSocket(1234);
   System.out.println("Listening");
   Socket sock = ssock.accept();
   ssock.close(); // no more connects
   PrintStream ps = new PrintStream(sock.getOutputStream());
   for (int i = 100; i >= 0; i--) {
     ps.println(i + " from Java Source and Support.");
   }
   ps.close();
   sock.close();
 }

}


 </source>
   
  
 
  



This server retrieves the time using the RFC867 protocol.

   <source lang="java">

/* Chapter 3 - Simple Protocols Java 2 Network Protocols Black Book by Al Williams Paraglyph Press 2001

  • /

import java.net.*; import java.io.*; public class Time867 {

   public static void main(String[] args) {
       String hostname = "tock.usno.navy.mil";
       if (args.length==1) hostname=args[0];
       try {
       int c;
       Socket sock=new Socket(hostname,13);
       InputStream is = sock.getInputStream();
       do {
         c=is.read();
         if (c!=-1) System.out.print((char)c);
          } while (c!=-1);
       }
       catch (IOException e) { System.out.println(e); }
   }

}


 </source>
   
  
 
  



URL Connection Test

   <source lang="java">

/**

* version 1.00 1999-08-27 author Cay Horstmann
*/

import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.FilterOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.URL; import java.net.URLConnection; public class URLConnectionTest {

 public static void main(String[] args) {
   try {
     String urlName;
     if (args.length > 0)
       urlName = args[0];
     else
       urlName = "http://java.sun.ru";
     URL url = new URL(urlName);
     URLConnection connection = url.openConnection();
     // set username, password if specified on command line
     if (args.length > 2) {
       String username = args[1];
       String password = args[2];
       String input = username + ":" + password;
       String encoding = base64Encode(input);
       connection.setRequestProperty("Authorization", "Basic "
           + encoding);
     }
     connection.connect();
     // print header fields
     int n = 1;
     String key;
     while ((key = connection.getHeaderFieldKey(n)) != null) {
       String value = connection.getHeaderField(n);
       System.out.println(key + ": " + value);
       n++;
     }
     // print convenience functions
     System.out.println("----------");
     System.out
         .println("getContentType: " + connection.getContentType());
     System.out.println("getContentLength: "
         + connection.getContentLength());
     System.out.println("getContentEncoding: "
         + connection.getContentEncoding());
     System.out.println("getDate: " + connection.getDate());
     System.out.println("getExpiration: " + connection.getExpiration());
     System.out.println("getLastModifed: "
         + connection.getLastModified());
     System.out.println("----------");
     BufferedReader in = new BufferedReader(new InputStreamReader(
         connection.getInputStream()));
     // print first ten lines of contents
     String line;
     n = 1;
     while ((line = in.readLine()) != null && n <= 10) {
       System.out.println(line);
       n++;
     }
     if (line != null)
       System.out.println(". . .");
   } catch (IOException exception) {
     System.out.println("Error: " + exception);
   }
 }
 public static String base64Encode(String s) {
   ByteArrayOutputStream bOut = new ByteArrayOutputStream();
   Base64OutputStream out = new Base64OutputStream(bOut);
   try {
     out.write(s.getBytes());
     out.flush();
   } catch (IOException exception) {
   }
   return bOut.toString();
 }

} /*

* BASE64 encoding encodes 3 bytes into 4 characters.
* |11111122|22223333|33444444| Each set of 6 bits is encoded according to the
* toBase64 map. If the number of input bytes is not a multiple of 3, then the
* last group of 4 characters is padded with one or two = signs. Each output
* line is at most 76 characters.
*/

class Base64OutputStream extends FilterOutputStream {

 public Base64OutputStream(OutputStream out) {
   super(out);
 }
 public void write(int c) throws IOException {
   inbuf[i] = c;
   i++;
   if (i == 3) {
     super.write(toBase64[(inbuf[0] & 0xFC) >> 2]);
     super.write(toBase64[((inbuf[0] & 0x03) << 4)
         | ((inbuf[1] & 0xF0) >> 4)]);
     super.write(toBase64[((inbuf[1] & 0x0F) << 2)
         | ((inbuf[2] & 0xC0) >> 6)]);
     super.write(toBase64[inbuf[2] & 0x3F]);
     col += 4;
     i = 0;
     if (col >= 76) {
       super.write("\n");
       col = 0;
     }
   }
 }
 public void flush() throws IOException {
   if (i == 1) {
     super.write(toBase64[(inbuf[0] & 0xFC) >> 2]);
     super.write(toBase64[(inbuf[0] & 0x03) << 4]);
     super.write("=");
     super.write("=");
   } else if (i == 2) {
     super.write(toBase64[(inbuf[0] & 0xFC) >> 2]);
     super.write(toBase64[((inbuf[0] & 0x03) << 4)
         | ((inbuf[1] & 0xF0) >> 4)]);
     super.write(toBase64[(inbuf[1] & 0x0F) << 2]);
     super.write("=");
   }
 }
 private static char[] toBase64 = { "A", "B", "C", "D", "E", "F", "G", "H",
     "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
     "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h",
     "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u",
     "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7",
     "8", "9", "+", "/" };
 private int col = 0;
 private int i = 0;
 private int[] inbuf = new int[3];

}


 </source>