Java/Network Protocol/Server
Содержание
- 1 A generic framework for a flexible, multi-threaded server
- 2 A multithreaded server
- 3 A server can use specialized streams to deliver typed data
- 4 Base class to build multithreaded servers easily
- 5 Client and Server Demo
- 6 Client estimates the speed of the network connection to the server
- 7 Logging Server based on SocketServer
- 8 Manage a pool of threads for clients
- 9 Quote Server
- 10 Reflector
- 11 Serve entire objects using ObjectOutputStream
- 12 Server allows connections on socket 6123
- 13 The client can specify information to control the output of a server
- 14 This server displays messages to a single client
- 15 This server retrieves the time using the RFC867 protocol.
- 16 URL Connection Test
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>