This is a very flexible generic http server by David Flanagan from the Java In A Nutshell series. I've made superficial alterations: bringing it up to date for Java generics and cutting out some Service examples, originally included in the Server class, which are given as separate code examples on THIS page.

What makes this server interesting is its implementation of its service method by loading a class with interface Service through reflection. The Server class allows wholly new services to be be loaded and run without even stopping the server. This is done through the Control class, itself an implementation of Service.

My current feeling is that this class is both concise enough to be an excellent guide to Socket programming in Java and sophisticated enough to run for serious purposes. The code is HERE.

 * 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



import java.util.*;

 * 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 {
    // This is the state for the server
    Map<Integer, Listener> services; // Hashtable mapping ports to Listeners
    Set<Connection> 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) {
        log("Starting server");
        threadGroup = new ThreadGroup(Server.class.getName());
        this.maxConnections = maxConnections;
        services = new HashMap<Integer, Listener>();
        connections = new HashSet<Connection>(maxConnections);

     * 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

                    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> ... ]");

     * 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);

    /** Write the specified object to the log */
    protected void log(Object o) {

     * 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 " +
        // Start the listener running.

     * 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) {

        // Ask the listener to stop
        // Remove it from the hashtable
        // And log it.
        log("Stopping service " + listener.service.getClass().getName() +
                " on port " + port);

     * 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");
                // And close the connection to the rejected client.
                // And log it, of course
                log("Connection refused to " +
                        s.getInetAddress().getHostAddress() + ":" + s.getPort() +
                        ": max connections reached.");
            } catch (IOException 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
            // Log this new connection
            log("Connected to " + s.getInetAddress().getHostAddress() + ":" +
                    s.getPort() + " on port " + s.getLocalPort() + " for service " +
            // And start the Connection thread to provide the service

     * 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) {
        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);
            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);
            out.print("CONNECTED TO " +
                    c.client.getInetAddress().getHostAddress() + ":" +
                    c.client.getPort() + " ON PORT " + c.client.getLocalPort() +
                    " FOR SERVICE " + c.service.getClass().getName() + "\n");

     * 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;

     * 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
            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 {
            } // 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) {

     * 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() + ":" +
            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) {
            } finally {

     * 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");

                } 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());
                            out.print("MAX CONNECTIONS CHANGED\n");
                    } else if (command.equals("status")) { // Status Display

                        if (!authorized) {
                            out.print("PASSWORD REQUIRED\n");
                        } else {
                    } 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) {
                    // If an exception occurred during the command, print an
                    // error message, then output details of the exception.
                    out.print("ERROR WHILE PARSING OR EXECUTING COMMAND:\n" +
                            e + "\n");

            // Finally, when the loop command loop ends, close the streams
            // and set our connected flag to false so that other clients can
            // now connect.
            connected = false;