import java.net.*; import java.io.*; import java.util.Date; import java.util.concurrent.ArrayBlockingQueue; /** * This program is a server that takes connection requests on * the port specified by the constant LISTENING_PORT. When a * connection is opened, the program sends the current time to * the connected socket. The program will continue to receive * and process connections until it is killed (by a CONTROL-C, * for example). * * This version of the program uses a thread pool of worker * threads that handle the connections. */ public class DateServerWithThreadPool { public static final int LISTENING_PORT = 32007; private static final int THREAD_POOL_SIZE = 5; private static final int QUEUE_CAPACITY = 10; /** * The connectionQueue is used to send connected sockets from the * main program to the worker threads. When a connection request * is received, the connected socket is placed into the queue. * Worker threads retrieve sockets from the queue as they become * available. This is an ArrayBlockingQueue, with a limited * capacity, to prevent the number of clients who are waiting * for service in the queue from becoming too large. */ private static ArrayBlockingQueue connectionQueue; public static void main(String[] args) { ServerSocket listener; // Listens for incoming connections. Socket connection; // For communication with the connecting program. /* Create a listening socket, create the thread pool, then accept and * process connection requests forever. Note that the connection queue * MUST be created before the threads are created, since a thread tries * to use the queue as soon as it is started. Once created, the thread * will immediately block until a socket becomes available in the queue. */ try { listener = new ServerSocket(LISTENING_PORT); connectionQueue = new ArrayBlockingQueue(QUEUE_CAPACITY); for (int i = 0; i < THREAD_POOL_SIZE; i++) { new ConnectionHandler(); // Create the thread; it starts itself. } System.out.println("Listening on port " + LISTENING_PORT); while (true) { // Accept next connection request and put it in the queue. connection = listener.accept(); try { connectionQueue.put(connection); // Blocks if queue is full. } catch (InterruptedException e) { } } } catch (Exception e) { System.out.println("Sorry, the server has shut down."); System.out.println("Error: " + e); return; } } // end main() /** * Defines one of the threads in the thread pool. Each thread runs * in an infinite loop in which it takes a connection from the connection * queue and handles communication with that client. The thread starts * itself in its constructor. The constructor also sets the thread * to be a daemon thread. (A program will end if all remaining * threads are daemon threads.) */ private static class ConnectionHandler extends Thread { ConnectionHandler() { setDaemon(true); start(); } public void run() { while (true) { Socket client; try { client = connectionQueue.take(); } catch (InterruptedException e) { continue; // (If interrupted, just go back to start of while loop.) } String clientAddress = client.getInetAddress().toString(); try { System.out.println("Connection from " + clientAddress ); System.out.println("Handled by thread " + this); Date now = new Date(); // The current date and time. PrintWriter outgoing; // Stream for sending data. outgoing = new PrintWriter( client.getOutputStream() ); outgoing.println( now.toString() ); outgoing.flush(); // Make sure the data is actually sent! client.close(); } catch (Exception e){ System.out.println("Error on connection with: " + clientAddress + ": " + e); } } } } } //end class DateServerWithThreadPool