Server Sockets

Each connection has two ends: the client, which initiates the connection, and the server, which responds to the connection. So far, I've only discussed the client side and assumed that a server existed out there for the client to talk to. To implement a server, you need to write a program that waits for other hosts to connect to it. A server socket binds to a particular port on the local machine (the server). Then it listens for incoming connection attempts from remote machines (the clients). When the server detects a connection attempt, it accepts the connection. This creates a socket between the two machines over which the client and the server communicate.

Multiple clients can connect to a server simultaneously. Incoming data is distinguished by the port to which it is addressed and the client host and port from which it came. The server can tell which service (such as HTTP or FTP) the data is intended for by checking the port at which it arrives. It knows where to send any response by looking at the client address and port stored with the data.

No more than one server socket can listen to a particular port at one time. Therefore, since a server may need to handle many connections at once, server programs tend to be multithreaded. (Alternately, they can use nonblocking I/O. We'll explore this starting in Chapter 16.) Generally, the server socket listening on the port only accepts the connections. It passes off the actual processing of each connection to a separate thread. Incoming connections are stored in a queue until the server can accept them. On most systems, the default queue length is between 5 and 50. Once the queue fills up, further incoming connections are refused until space in the queue opens up.

The java.net.ServerSocket class represents a server socket. The constructors receive the port to bind to, the queue length for incoming connections, and the IP address:

When you create a ServerSocket object, it attempts to bind to the port given by the port argument. If another server socket is already listening to the port, the constructor throws an IOExceptionmore specifically, a java.net.BindException. Only one server socket can listen to a particular port at a time. This includes server sockets opened by non-Java programs. For example, if there's already an HTTP server running on port 80, you won't be able to bind to port 80.

On Unix systems, including Mac OS X but not Windows, the program must be running as root to bind to a port between 1 and 1023. Otherwise, accept( ) tHRows a BindException.

0 is a special port number. It tells Java to pick an available port. You can then find out which port it has picked with the getLocalPort( ) method:

public int getLocalPort( )

This is useful if the client and the server have already established a separate channel of communication over which the chosen port number can be communicated. For example, the FTP protocol uses two sockets. The client makes the initial connection to the server on a socket it will use to send commands. The client also opens a server socket on a random port on the local host. One of the commands it sends tells the server the port number on which the client is listening. The server then opens a socket to the client's server port, which it uses to send files. Because commands and data are sent over two different sockets, a long file doesn't tie up the command channel.

Once you have a ServerSocket, you wait for incoming connections by calling the accept( ) method. This method blocks until a connection attempt occurs and then returns a Socket that you can use to communicate with the client.

public Socket accept( ) throws IOException

The close( ) method terminates the ServerSocket:

public void close( ) throws IOException

That's pretty much all there is to the ServerSocket, except for a few methods dealing with socket options and some other details. In particular, there aren't methods for getting input and output streams. Instead, accept( ) returns a client Socket object: this Socket's getInputStream( ) or getOutputStream( ) methods return the streams used to communicate. For example:

Notice in this example, I closed the Socket s, not the ServerSocket ss. ss is still bound to port 2345. You get a new socket for each connection and reuse the server socket. For example, the next code fragment repeatedly accepts connections:

Here's some output from this server. The server is running on utopia.poly.edu. The client is connecting from titan.oit.unc.edu. Note how the port from which the connection comes changes each time; like most client programs, the telnet program picks an arbitrary local port for outgoing connections:

If you aren't able to make a connection to this server, check your firewall rules. For security, most modern networks install firewalls in either the router, the local host, or both that prevent all connections to unrecognized services and ports. You may need to configure your firewall(s) to allow connections to port 2345 to run this program.