package kvstore; import java.io.IOException; import java.net.InetSocketAddress; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketTimeoutException; /** * This is a generic class that should handle all TCP network connections * arriving on a unique (hostname, port) tuple. Ensure that this class * remains generic by providing the connection handling logic in a * NetworkHandler. */ public class SocketServer { public String hostname; public int port; public ServerSocket server; public NetworkHandler handler; public boolean stopped = false; public static final int TIMEOUT = 100; /** * Construct a SocketServer with a ServerSocket listening on a free port. */ public SocketServer(String hostname) { this(hostname, 0); } /** * Construct a SocketServer with a ServerSocket listening on the port * passed in. * * @param port port on which to listen for connections */ public SocketServer(String hostname, int port) { this.hostname = hostname; this.port = port; } public String getHostname() { return this.hostname; } public int getPort() { return this.port; } /** * Add the network handler for this socket server * * @param handler is logic for servicing a network connection */ public void addHandler(NetworkHandler handler) { this.handler = handler; } /** * Creates a new ServerSocket and binds it to an endpoint. * If the given port is 0, the ServerSocket should be bound to an * automatically allocated port. See ServerSocket documentation for details. * * @throws IOException if unable create and bind a ServerSocket */ public void connect() throws IOException { server = new ServerSocket(port, 0, InetAddress.getByName(hostname)); if(port == 0) port = server.getLocalPort(); server.setSoTimeout(TIMEOUT); } /** * Accept and save requests as jobs to be serviced asynchronously. * A call to stop() should result in the closing of the ServerSocket * within TIMEOUT milliseconds. * * @throws IOException if there is an unexpected network error while * listening for or servicing requests */ public void start() throws IOException { while(!stopped) { Socket s; try { s = server.accept(); System.out.println("Incoming connection accepted."); if(handler != null) handler.handle(s); } catch(SocketTimeoutException e) {} } } /** * Stops the ServerSocket cleanly (does not force an exception to be thrown). * A call to stop() will result in the closing of the server no more than * TIMEOUT milliseconds later. That logic should be implemented in start(). */ public void stop() { stopped = true; } }