The Server Class
The
AbstractConnection class was written to connect clients with remote services. What you need now is a way to wait for incoming client requests and spawns these services. The following Server class does just that. The Server class defines a port number and ServerSocket object to listen for connections and implements the Runnable interface so that it can enter an infinite loop to listen for and create service connections. Check out the code below.
import java.io.*;
import java.net.*;
// a simple server that sits and listens for remote connection requests
// the service request is then delegated to the createService method
public abstract class Server implements Runnable
{
// the default port for server connections
public static final int DEFAULT_PORT = 1234;
// the port the service is located on
protected int port;
// a ServerSocket for listening for service requests
protected ServerSocket listener;
// a thread of execution for the server
protected Thread exec;
// exit with an error message when an exception occurs
public static void fail(Exception e, String msg)
{
System.err.println(msg + ": " + e);
System.exit(1);
}
// creates a new Server object with the specified port
public Server(int portNo)
{
// set the port, making sure it is non-negative and non-zero
port = (portNo <= 0) ? DEFAULT_PORT : portNo;
try
{
listener = new ServerSocket(port);
}
catch (Exception e)
{
fail(e, "Exception occurred while creating server socket");
}
exec = new Thread(this);
}
// starts the execution thread
public final void start()
{
exec.start();
}
// creates a service with the specified Socket
protected abstract void createService(Socket socket);
// the main workhorse of the server thread
// listen for and accept connections from clients
public void run()
{
System.out.println("Server: listening on port " + port);
System.out.println("Server: use Ctrl-C to terminate service.");
try
{
Thread thread = Thread.currentThread();
while(exec == thread)
{
// listen for and accept the connection
Socket clientSocket = listener.accept();
// create the service using the accepted Socket
createService(clientSocket);
// print a connected message to the console
System.out.println("\nConnected to " +
clientSocket.getInetAddress() +
" : " + clientSocket.getPort());
try
{
Thread.sleep(25);
}
catch(InterruptedException e)
{ }
}
}
catch (IOException e)
{
fail(e, "Exception while listening for connections");
}
}
} // Server
The Server constructor creates a new
ServerSocket object at the specified port. The ServerSocket class listens to a specified port and returns a new Socket object for the service to use when a connection is requested from a client. After creating a Server object, you should then invoke its start method to begin the listening thread. The Server class is declared as abstract in order to keep it as flexible and reusable as possible. Classes that extend the Server class will be responsible for overriding the createService method and spawning another Thread object for providing the actual service. This structure will allow the Server class to perform a single purpose, and that is to accept remote client connections.
The Server class includes no graphical features. Rather, it is run entirely from the command line instead. Since it runs in an infinite loop, you will need a way to terminate the program when you are finished using it. Like any console program, pressing Ctrl-C will terminate it and return you to the shell prompt.