10.1 The ServerSocket Class

     

The ServerSocket class contains everything needed to write servers in Java. It has constructors that create new ServerSocket objects, methods that listen for connections on a specified port, methods that configure the various server socket options, and the usual miscellaneous methods such as toString( ) .

In Java, the basic life cycle of a server program is:

  1. A new ServerSocket is created on a particular port using a ServerSocket( ) constructor.

  2. The ServerSocket listens for incoming connection attempts on that port using its accept( ) method. accept( ) blocks until a client attempts to make a connection, at which point accept( ) returns a Socket object connecting the client and the server.

  3. Depending on the type of server, either the Socket 's getInputStream() method, getOutputStream( ) method, or both are called to get input and output streams that communicate with the client.

  4. The server and the client interact according to an agreed-upon protocol until it is time to close the connection.

  5. The server, the client, or both close the connection.

  6. The server returns to step 2 and waits for the next connection.

If step 4 is likely to take a long or indefinite amount of time, traditional Unix servers such as wu- ftpd create a new process to handle each connection so that multiple clients can be serviced at the same time. Java programs should spawn a thread to interact with the client so that the server can be ready to process the next connection sooner. A thread places a far smaller load on the server than a complete child process. In fact, the overhead of forking too many processes is why the typical Unix FTP server can't handle more than roughly 400 connections without slowing to a crawl. On the other hand, if the protocol is simple and quick and allows the server to close the connection when it's through, then it will be more efficient for the server to process the client request immediately without spawning a thread.

Although threads are lighter-weight than processes on most systems (Linux is the notable exception), too many threads can still be a performance problem. For instance, on most VMs each thread requires about a megabyte of RAM above and beyond what the rest of the program needs. Thus, on a typical modern server with about a gigabyte of RAM, anything close to or beyond a thousand threads is likely to slow down dramatically and eventually crash as the CPU violently and frequently swaps data into and out of RAM. Spawning too many threads is one of the few ways you can reliably crash any Java virtual machine.

Java 1.4 introduces a ServerSocketChannel class that provides non-blocking , multiplexed I/O based on channels rather than streams. With channels, a single thread can process multiple connections, thereby requiring many fewer threads and placing a much smaller load on the VM. This can be highly advantageous for high volume servers on some operating systems. I'll discuss these kinds of servers in Chapter 12. For simple, low-volume servers or any servers that need to run with Java 1.3 or earlier, the techniques discussed in this chapter should be used.


The operating system stores incoming connection requests addressed to a particular port in a first-in, first-out queue. The default length of the queue is normally 50, although it can vary from operating system to operating system. Some operating systems (not Solaris) have a maximum queue length, typically five. On these systems, the queue length will be the largest possible value less than or equal to 50. After the queue fills to capacity with unprocessed connections, the host refuses additional connections on that port until slots in the queue open up. Many (though not all) clients will try to make a connection multiple times if their initial attempt is refused . The operating system manages incoming connections and the queue; your program does not need to worry about it. Several ServerSocket constructors allow you to change the length of the queue if its default length isn't large enough; however, you won't be able to increase the queue beyond the maximum size that the operating system supports.

10.1.1 The Constructors

There are four public ServerSocket constructors:

 public ServerSocket(int port) throws BindException, IOException public ServerSocket(int port, int queueLength)   throws BindException, IOException public ServerSocket(int port, int queueLength, InetAddress bindAddress)   throws IOException public ServerSocket( ) throws IOException  // Java 1.4 

These constructors let you specify the port, the length of the queue used to hold incoming connection requests, and the local network interface to bind to. They pretty much all do the same thing, though some use default values for the queue length and the address to bind to. Let's explore these in order.

10.1.1.1 public ServerSocket(int port) throws BindException, IOException

This constructor creates a server socket on the port specified by the argument. If you pass 0 for the port number, the system selects an available port for you. A port chosen for you by the system is sometimes called an anonymous port since you don't know its number. For servers, anonymous ports aren't very useful because clients need to know in advance which port to connect to; however, there are a few situations (which we will discuss later) in which an anonymous port might be useful.

For example, to create a server socket that would be used by an HTTP server on port 80, you would write:

 try {   ServerSocket httpd = new ServerSocket(80); } catch (IOException ex) {   System.err.println(ex); } 

The constructor throws an IOException ( specifically , a BindException ) if the socket cannot be created and bound to the requested port. An IOException when creating a ServerSocket almost always means one of two things. Either another server socket, possibly from a completely different program, is already using the requested port, or you're trying to connect to a port from 1 to 1,023 on Unix (including Linux and Mac OS X) without root (superuser) privileges.

You can use this constructor to write a variation on the PortScanner programs of the previous chapter. Example 10-1 checks for ports on the local machine by attempting to create ServerSocket objects on them and seeing on which ports that fails. If you're using Unix and are not running as root, this program works only for ports 1,024 and above.

Example 10-1. Look for local ports
 import java.net.*; import java.io.*; public class LocalPortScanner {   public static void main(String[] args) {          for (int port = 1; port <= 65535; port++) {       try {         // the next line will fail and drop into the catch block if         // there is already a server running on the port         ServerSocket server = new ServerSocket(port);       }       catch (IOException ex) {         System.out.println("There is a server on port " + port + ".");       } // end catch     } // end for   }    } 

Here's the output I got when running LocalPortScanner on my Windows NT 4.0 workstation:

 D:\JAVA\JNP2\examples>  java LocalPortScanner  There is a server on port 135. There is a server on port 1025. There is a server on port 1026. There is a server on port 1027. There is a server on port 1028. 

10.1.1.2 public ServerSocket(int port, int queueLength) throws IOException, BindException

This constructor opens a server socket on the specified port with a queue length of your choosing. If the machine has multiple network interfaces or IP addresses, then it listens on this port on all those interfaces and IP addresses. The queueLength argument sets the length of the queue for incoming connection requeststhat is, how many incoming connections can be stored at one time before the host starts refusing connections. Some operating systems have a maximum queue length, typically five. If you try to expand the queue past that maximum number, the maximum queue length is used instead. If you pass 0 for the port number, the system selects an available port.

For example, to create a server socket on port 5,776 that would hold up to 100 incoming connection requests in the queue, you would write:

 try {   ServerSocket httpd = new ServerSocket(5776, 100); } catch (IOException ex) {   System.err.println(ex); } 

The constructor throws an IOException (specifically, a BindException ) if the socket cannot be created and bound to the requested port. However, no exception is thrown if the queue length is larger than the host OS supports. Instead, the queue length is simply set to the maximum size allowed.

10.1.1.3 public ServerSocket(int port, int queueLength, InetAddress bindAddress) throws BindException, IOException

This constructor binds a server socket to the specified port with the specified queue length. It differs from the other two constructors in binding only to the specified local IP address. This constructor is useful for servers that run on systems with several IP addresses because it allows you to choose the address to which you'll listen. That is, the server socket only listens for incoming connections on the specified address; it won't listen for connections that come in through the host's other addresses. The previous two constructors bind to all local IP addresses by default.

For example, login. ibiblio .org is a particular Linux box in North Carolina. It's connected to the Internet with the IP address 152.2.210.122. The same box has a second Ethernet card with the local IP address 192.168.210.122 that is not visible from the public Internet, only from the local network. If for some reason I wanted to run a server on this host that only responded to local connections from within the same network, I could create a server socket that listens on port 5,776 of 192.168.210.122 but not on port 5,776 of 152.2.210.122, like so:

 try {   ServerSocket httpd = new ServerSocket(5776, 10,     InetAddress.getByName("192.168.210.122")); } catch (IOException ex) {   System.err.println(ex); } 

The constructor throws an IOException (again, really a BindException ) if the socket cannot be created and bound to the requested port or network interface.

10.1.1.4 public ServerSocket( ) throws IOException // Java 1.4

The public no-args constructor is new in Java 1.4. It creates a ServerSocket object but does not actually bind it to a port so it cannot initially accept any connections. It can be bound later using the bind() methods also introduced in Java 1.4:

 public void bind(SocketAddress endpoint) throws IOException // Java 1.4 public void bind(SocketAddress endpoint, int queueLength) // Java 1.4   throws IOException 

The primary use for this feature is to allow programs to set server socket options before binding to a port. Some options are fixed after the server socket has been bound. The general pattern looks like this:

 ServerSocket ss = new ServerSocket( ); // set socket options... SocketAddress  http = new InetSocketAddress(80); ss.bind(http); 

You can also past null for the SocketAddress to select an arbitrary port. This is like passing 0 for the port number in the other constructors.

10.1.2 Accepting and Closing Connections

A ServerSocket customarily operates in a loop that repeatedly accepts connections. Each pass through the loop invokes the accept( ) method. This returns a Socket object representing the connection between the remote client and the local server. Interaction with the client takes place through this Socket object. When the transaction is finished, the server should invoke the Socket object's close() method. If the client closes the connection while the server is still operating, the input and/or output streams that connect the server to the client throw an InterruptedIOException on the next read or write. In either case, the server should then get ready to process the next incoming connection. However, when the server needs to shut down and not process any further incoming connections, you should invoke the ServerSocket object's close( ) method.

10.1.2.1 public Socket accept( ) throws IOException

When server setup is done and you're ready to accept a connection, call the ServerSocket 's accept() method. This method "blocks"; that is, it stops the flow of execution and waits until a client connects. When a client does connect, the accept( ) method returns a Socket object. You use the streams returned by this Socket 's getInputStream( ) and getOutputStream( ) methods to communicate with the client. For example:

 ServerSocket server = new ServerSocket(5776); while (true) {   Socket connection = server.accept( );   OutputStreamWriter out     = new OutputStreamWriter(connection.getOutputStream( ));   out.write("You've connected to this server. Bye-bye now.\r\n");           connection.close( ); } 

If you don't want the program to halt while it waits for a connection, put the call to accept( ) in a separate thread.

If you're using Java 1.4 or later, you have the option to use channels and non-blocking I/O instead of threads. In some (not all) virtual machines, this is much faster than using streams and threads. These techniques will be discussed in Chapter 12.


When exception handling is added, the code becomes somewhat more convoluted. It's important to distinguish between exceptions that should probably shut down the server and log an error message, and exceptions that should just close that active connection. Exceptions thrown by accept( ) or the input and output streams generally should not shut down the server. Most other exceptions probably should. To do this, you'll need to nest your try blocks.

Finally, most servers will want to make sure that all sockets they accept are closed when they're finished. Even if the protocol specifies that clients are responsible for closing connections, clients do not always strictly adhere to the protocol. The call to close( ) also has to be wrapped in a try block that catches an IOException . However, if you do catch an IOException when closing the socket, ignore it. It just means that the client closed the socket before the server could. Here's a slightly more realistic example:

 try {   ServerSocket server = new ServerSocket(5776);   while (true) {     Socket connection = server.accept( );     try {       Writer out         = new OutputStreamWriter(connection.getOutputStream( ));       out.write("You've connected to this server. Bye-bye now.\r\n");        out.flush( );              connection.close( );    }    catch (IOException ex) {      // This tends to be a transitory error for this one connection;      // e.g. the client broke the connection early. Consequently,      // you don't want to break the loop or print an error message.      // However, you might choose to log this exception in an error log.    }    finally {      // Guarantee that sockets are closed when complete.       try {        if (connection != null) connection.close( );      }      catch (IOException ex) {}    } } catch (IOException ex) {   System.err.println(ex); } 

Example 10-2 implements a simple daytime server, as per RFC 867. Since this server just sends a single line of text in response to each connection, it processes each connection immediately. More complex servers should spawn a thread to handle each request. In this case, the overhead of spawning a thread would be greater than the time needed to process the request.

If you run this program on Unix (including Linux and Mac OS X), you need to run it as root in order to connect to port 13. If you don't want to or can't run it as root, change the port number to something above 1024say, 1313.


Example 10-2. A daytime server
 import java.net.*; import java.io.*; import java.util.Date;   public class DaytimeServer {     public final static int DEFAULT_PORT = 13;   public static void main(String[] args) {    int port = DEFAULT_PORT;         if (args.length > 0) {      try {         port = Integer.parseInt(args[0]);         if (port < 0  port >= 65536) {           System.out.println("Port must between 0 and 65535");           return;               }      }         catch (NumberFormatException ex) {        // use default port      }      }         try {           ServerSocket server = new ServerSocket(port);             Socket connection = null;      while (true) {                 try {          connection = server.accept( );          Writer out = new OutputStreamWriter(connection.getOutputStream( ));          Date now = new Date( );          out.write(now.toString( ) +"\r\n");          out.flush( );                connection.close( );        }        catch (IOException ex) {}        finally {          try {            if (connection != null) connection.close( );          }          catch (IOException ex) {}                  }                }  // end while            }  // end try    catch (IOException ex) {      System.err.println(ex);    } // end catch   } // end main } // end DaytimeServer 

Example 10-2 is straightforward. The first three lines import the usual packages, java.io and java.net , as well as java.util.Date , which provides the time as read by the server's internal clock. There is a single public final static int field (i.e., a constant) in the class DEFAULT_PORT , which is set to the well-known port for a daytime server (port 13). The class has a single method, main( ) , which does all the work. If the port is specified on the command line, then it's read from args[0] . Otherwise, the default port is used.

The outer try block traps any IOException s that may arise while the ServerSocket object server is constructed on the daytime port or when it accepts connections. The inner try block watches for exceptions thrown while the connections are accepted and processed . The accept( ) method is called within an infinite loop to watch for new connections; like many servers, this program never terminates but continues listening until an exception is thrown or you stop it manually.

The command for stopping a program manually depends on your system; under Unix, NT, and many other systems, CTRL-C will do the job. If you are running the server in the background on a Unix system, stop it by finding the server's process ID and killing it with the kill command ( kill pid ) .


When a client connects, accept( ) returns a Socket , which is stored in the local variable connection , and the program continues. It calls getOutputStream( ) to get the output stream associated with that Socket and then chains that output stream to a new OutputStreamWriter , out . A new Date object provides the current time. The content is sent to the client by writing its string representation on out with write() .

Finally, after the data is sent or an exception has been thrown, the finally block closes the connection . Always close a socket when you're finished with it. In the previous chapter, I said that a client shouldn't rely on the other side of a connection to close the socket: that goes triple for servers. Clients time out or crash; users cancel transactions; networks go down in high-traffic periods. For any of these or a dozen more reasons, you cannot rely on clients to close sockets, even when the protocol requires them to, which this one doesn't.

Sending binary, nontext data is not significantly harder. Example 10-3 demonstrates with a time server that follows the time protocol outlined in RFC 868. When a client connects, the server sends a 4-byte, big-endian, unsigned integer specifying the number of seconds that have passed since 12:00 A.M., January 1, 1900 GMT (the epoch ). Once again, the current time is found by creating a new Date object. However, since the Date class counts milliseconds since 12:00 A.M., January 1, 1970 GMT rather than seconds since 12:00 A.M., January 1, 1900 GMT, some conversion is necessary.

Example 10-3. A time server
 import java.net.*; import java.io.*; import java.util.Date;   public class TimeServer {     public final static int DEFAULT_PORT = 37;   public static void main(String[] args) {             int port = DEFAULT_PORT;         if (args.length > 0) {      try {         port = Integer.parseInt(args[0]);         if (port < 0  port >= 65536) {           System.out.println("Port must between 0 and 65535");           return;               }      }         catch (NumberFormatException ex) {}      }         // The time protocol sets the epoch at 1900,    // the Date class at 1970. This number     // converts between them.         long differenceBetweenEpochs = 2208988800L;         try {      ServerSocket server = new ServerSocket(port);        while (true) {          Socket connection = null;          try {            connection = server.accept( );            OutputStream out = connection.getOutputStream( );            Date now = new Date( );            long msSince1970 = now.getTime( );            long secondsSince1970 = msSince1970/1000;            long secondsSince1900 = secondsSince1970              + differenceBetweenEpochs;            byte[] time = new byte[4];            time[0]              = (byte) ((secondsSince1900 & 0x00000000FF000000L) >> 24);            time[1]              = (byte) ((secondsSince1900 & 0x0000000000FF0000L) >> 16);            time[2]              = (byte) ((secondsSince1900 & 0x000000000000FF00L) >> 8);            time[3] = (byte) (secondsSince1900 & 0x00000000000000FFL);            out.write(time);            out.flush( );                } // end try          catch (IOException ex) {          } // end catch          finally {            if (connection != null) connection.close( );           }        }  // end while    }  // end try    catch (IOException ex) {      System.err.println(ex);    } // end catch   } // end main } // end TimeServer 

As with the TimeClient of the previous chapter, most of the effort here goes into working with a data format (32-bit unsigned integers) that Java doesn't natively support.

10.1.2.2 public void close( ) throws IOException

If you're finished with a server socket, you should close it, especially if the program is going to continue to run for some time. This frees up the port for other programs that may wish to use it. Closing a ServerSocket should not be confused with closing a Socket . Closing a ServerSocket frees a port on the local host, allowing another server to bind to the port; it also breaks all currently open sockets that the ServerSocket has accepted.

Server sockets are closed automatically when a program dies, so it's not absolutely necessary to close them in programs that terminate shortly after the ServerSocket is no longer needed. Nonetheless, it doesn't hurt. For example, the main loop of the LocalPortScanner program might be better written like this so that it doesn't temporarily occupy most of the ports on the system:

 for (int port = 1; port <= 65535; port++) {   try {     // the next line will fail and drop into the catch block if     // there is already a server running on the port     ServerSocket server = new ServerSocket(port);     server.close( );   }   catch (IOException ex) {     System.out.println("There is a server on port " + port + ".");   }  } // end for 

After the server socket has been closed, it cannot be reconnected, even to the same port.

Java 1.4 adds an isClosed( ) method that returns true if the ServerSocket has been closed, false if it hasn't:

 public boolean isClosed( ) // Java 1.4 

ServerSocket objects that were created with the no-args ServerSocket( ) constructor and not yet bound to a port are not considered to be closed. Invoking isClosed( ) on these objects returns false. Java 1.4 also adds an isBound( ) method that tells you whether the ServerSocket has been bound to a port:

 public boolean isBound( ) // Java 1.4 

As with the isBound( ) method of the Socket class discussed in the last chapter, the name is a little misleading. isBound( ) returns true if the ServerSocket has ever been bound to a port, even if it's currently closed. If you need to test whether a ServerSocket is open, you must check both that isBound( ) returns true and that isClosed( ) returns false. For example:

 public static boolean isOpen(ServerSocket ss) {   return ss.isBound( ) && ! ss.isClosed( ); } 

10.1.3 The get Methods

The ServerSocket class provides two getter methods that tell you the local address and port occupied by the server socket. These are useful if you've opened a server socket on an anonymous port and/or an unspecified network interface. This would be the case, for one example, in the data connection of an FTP session.

10.1.3.1 public InetAddress getInetAddress( )

This method returns the address being used by the server (the local host). If the local host has a single IP address (as most do), this is the address returned by InetAddress.getLocalHost( ) . If the local host has more than one IP address, the specific address returned is one of the host's IP addresses. You can't predict which address you will get. For example:

 ServerSocket httpd = new ServerSocket(80); InetAddress ia = httpd.getInetAddress( ); 

If the ServerSocket has not yet bound to a network interface, this method returns null.

10.1.3.2 public int getLocalPort( )

The ServerSocket constructors allow you to listen on an unspecified port by passing 0 for the port number. This method lets you find out what port you're listening on. You might use this in a peer-to-peer multisocket program where you already have a means to inform other peers of your location. Or a server might spawn several smaller servers to perform particular operations. The well-known server could inform clients what ports they can find the smaller servers on. Of course, you can also use getLocalPort() to find a non-anonymous port, but why would you need to? Example 10-4 demonstrates.

Example 10-4. A random port
 import java.net.*; import java.io.*; public class RandomPort {   public static void main(String[] args) {     try {       ServerSocket server = new ServerSocket(0);       System.out.println("This server runs on port "         + server.getLocalPort( ));     }     catch (IOException ex) {       System.err.println(ex);     }   } } 

Here's the output of several runs:

 D:\JAVA\JNP3\examples>  java RandomPort  This server runs on port 1154 D:\JAVA\JNP3\examples>  java RandomPort  This server runs on port 1155 D:\JAVA\JNP3\examples>  java RandomPort  This server runs on port 1156 

At least on this VM, the ports aren't really random, but they are at least indeterminate until runtime.

If the ServerSocket has not yet bound to a port, then this method returns -1.

10.1.4 Socket Options

Java 1.3 only supports one socket option for server sockets, SO_TIMEOUT. Java 1.4 adds two more, SO_REUSEADDR and SO_RCVBUF.

10.1.4.1 SO_TIMEOUT

SO_TIMEOUT is the amount of time, in milliseconds, that accept( ) waits for an incoming connection before throwing a java.io.InterruptedIOException . If SO_TIMEOUT is 0, accept( ) will never time out. The default is to never time out.

Using SO_TIMEOUT is rather rare. You might need it if you were implementing a complicated and secure protocol that required multiple connections between the client and the server where responses needed to occur within a fixed amount of time. However, most servers are designed to run for indefinite periods of time and therefore just use the default timeout value, 0 (never time out). If you want to change this, the setSoTimeout( ) method sets the SO_TIMEOUT field for this server socket object.

 public void setSoTimeout(int timeout) throws SocketException public int  getSoTimeout( ) throws IOException 

The countdown starts when accept() is invoked. When the timeout expires , accept( ) throws an InterruptedIOException . (In Java 1.4, it throws SocketTimeoutException , a subclass of InterruptedIOException .) You should set this option before calling accept( ) ; you cannot change the timeout value while accept( ) is waiting for a connection. The timeout argument must be greater than or equal to zero; if it isn't, the method throws an IllegalArgumentException . For example:

 try {   ServerSocket server = new ServerSocket(2048);   server.setSoTimeout(30000); // block for no more than 30 seconds   try {     Socket s = server.accept( );     // handle the connection     // ...   }   catch (InterruptedIOException ex) {     System.err.println("No connection within 30 seconds");   }   finally {     server.close( );   } catch (IOException ex) {   System.err.println("Unexpected IOException: " + e); } 

The getSoTimeout() method returns this server socket's current SO_TIMEOUT value. For example:

 public void printSoTimeout(ServerSocket server) {   int timeout = server.getSoTimeOut( );   if (timeout > 0) {     System.out.println(server + " will time out after "       + timeout + "milliseconds.");   }   else if (timeout == 0) {     System.out.println(server + " will never time out.");   }   else {     System.out.println("Impossible condition occurred in " + server);     System.out.println("Timeout cannot be less than zero." );   } } 

10.1.4.2 SO_REUSEADDR // Java 1.4

The SO_REUSEADDR option for server sockets is very similar to the same option for client sockets, discussed in the last chapter. It determines whether a new socket will be allowed to bind to a previously used port while there might still be data traversing the network addressed to the old socket. As you probably expect, there are two methods to get and set this option:

 public void setReuseAddress(boolean on) throws SocketException   public boolean getReuseAddress( ) throws SocketException 

The default value is platform-dependent. This code fragment determines the default value by creating a new ServerSocket and then calling getReuseAddress( ) :

 ServerSocket ss = new ServerSocket(10240); System.out.println("Reusable: " + ss.getReuseAddress( )); 

On the Linux and Mac OS X boxes where I tested this code, server sockets were reusable.

10.1.4.3 SO_RCVBUF // Java 1.4

The SO_RCVBUF option sets the default receive buffer size for client sockets accepted by the server socket. It's read and written by these two methods:

 public void setReceiveBufferSize(int size) throws SocketException public int  getReceiveBufferSize( ) throws SocketException 

Setting SO_RCVBUF on a server socket is like calling setReceiveBufferSize( ) on each individual socket returned by accept( ) (except that you can't change the receive buffer size after the socket has been accepted). Recall from the last chapter that this option suggests a value for the size of the individual IP packets in the stream. Faster connections will want to use larger packets, although most of the time the default value is fine.

You can set this option before or after the server socket is bound, unless you want to set a receive buffer size larger than 64K. In that case, you must set the option on an unbound ServerSocket before binding it. For example:

 ServerSocket ss = new ServerSocket( ); int receiveBufferSize = ss.getReceiveBufferSize( ); if (receiveBufferSize < 131072) {   ss.setReceiveBufferSize(131072); } ss.bind(new InetSocketAddress(8000)); //... 

10.1.4.4 public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) // Java 1.5

Java 1.5 adds a slightly different method for setting socket optionsthe setPerformancePreferences() method:

 public void setPerformancePreferences(int connectionTime, int latency,                                                       int bandwidth) 

This method expresses the relative preferences given to connection time, latency, and bandwidth. For instance, if connectionTime is 2 and latency is 1 and bandwidth is 3, then maximum bandwidth is the most important characteristic, minimum latency is the least important, and connection time is in the middle. Exactly how any given VM implements this is implementation-dependent. Indeed, it may be a no-op in some implementations . The API documentation for ServerSocket even suggests using non-TCP/IP sockets, although it's not at all clear what that means.

10.1.5 The Object Methods

ServerSocket overrides only one of the standard methods from java.lang.Object , toString( ) . Thus, equality comparisons test for strict identity and server sockets are problematic in hash tables. Normally, this isn't a large problem.

10.1.5.1 public String toString( )

A String returned by ServerSocket 's toString( ) method looks like this:

 ServerSocket[addr=0.0.0.0,port=0,localport=5776] 

addr is the address of the local network interface to which the server socket is bound. This will be 0.0.0.0 if it's bound to all interfaces, as is commonly the case. port is always 0. The localport is the local port on which the server is listening for connections. This method is sometimes useful for debugging, but not much more. Don't rely on it.

10.1.6 Implementation

The ServerSocket class provides two methods for changing the default implementation of server sockets. I'll describe them only briefly here, since they're primarily intended for implementers of Java virtual machines rather than application programmers.

10.1.6.1 public static void setSocketFactory(SocketImplFactory factory) throws IOException

This method sets the system's server SocketImplFactory , which is the factory used to create ServerSocket objects. This is not the same factory that is used to create client Socket objects, though the syntax is similar; you can have one factory for Socket objects and a different factory for ServerSocket objects. You can set this factory only once in a program, however. A second attempt to set the SocketImplFactory throws a SocketException .

10.1.6.2 protected final void implAccept(Socket s) throws IOException

Subclasses of ServerSocket use this method when they want to override accept( ) so that it returns an instance of their own custom Socket subclass rather than a plain java.net.Socket . The overridden accept( ) method passes its own unconnected Socket object to this method to actually make the connection. You pass an unconnected Socket object to implAccept( ) . When implAccept( ) returns, the Socket argument s is connected to a client. For example:

 public Socket accept( )  throws IOException {     Socket s = new MySocketSubclass( );     implAccept(s);     return s;   } 

If the server needs to know that the Socket returned by accept( ) has a more specific type than just java.net.Socket , it must cast the return value appropriately. For example:

 ServerSocket server = new MyServerSocketSubclass(80);   while (true) {     MySocketSubclass  socket = (MySocketSubclass) server.accept( );;      // ...   } 



Java Network Programming
Java Network Programming, Third Edition
ISBN: 0596007213
EAN: 2147483647
Year: 2003
Pages: 164

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net