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:
- A new
ServerSocket
is created on a particular port using aServerSocket( )
constructor. - The
ServerSocket
listens for incoming connection attempts on that port using itsaccept( )
method.accept( )
blocks until a client attempts to make a connection, at which pointaccept( )
returns aSocket
object connecting the client and the server. - Depending on the type of server, either the
Socket
'sgetInputStream()
method,getOutputStream( )
method, or both are called to get input and output streams that communicate with the client. - The server and the client interact according to an agreed-upon protocol until it is time to close the connection.
- The server, the client, or both close the connection.
- 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 . 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 There are four public 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.
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:
The constructor throws an Here's the output I got when running 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 The constructor throws an 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:
The constructor throws an The public no-args constructor is new in Java 1.4. It creates a 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:
You can also past null for the A When server setup is done and you're ready to accept a connection, call the If you don't want the program to halt while it waits for a connection, put the call to 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 .
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 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 1024-say, 1313.
Example 10-2 is straightforward. The first three lines import the usual packages, 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 When a client connects, As with the 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 After the server socket has been closed, it cannot be reconnected, even to the same port. Java 1.4 adds an As with the The 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 If the The Here's the output of several runs:
At least on this VM, the ports aren't really random, but they are at least indeterminate until runtime. If the Java 1.3 only supports one socket option for server sockets, SO_TIMEOUT. Java 1.4 adds two more, SO_REUSEADDR and SO_RCVBUF.
SO_TIMEOUT is the amount of time, in milliseconds, that The countdown starts when The 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:
The default value is platform-dependent. This code fragment determines the default value by creating a new On the Linux and Mac OS X boxes where I tested this code, server sockets were reusable.
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:
Setting SO_RCVBUF on a server socket is like calling Java 1.5 adds a slightly different method for setting socket options-the This method expresses the relative preferences given to connection time, latency, and bandwidth. For instance, if A The This method sets the system's server Subclasses of If the server needs to know that the 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.
The Constructors
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
public ServerSocket(int port) throws BindException, IOException
try {
ServerSocket httpd = new ServerSocket(80);
}
catch (IOException ex) {
System.err.println(ex);
}
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
}
}
LocalPortScanner
on my Windows NT 4.0 workstation:
D:\JAVA\JNP2\examples\11>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.
public ServerSocket(int port, int queueLength) throws IOException, BindException
queueLength
argument sets the length of the queue for incoming connection requests-that 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);
}
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.
public ServerSocket(int port, int queueLength, InetAddress bindAddress) throws BindException, IOException
try {
ServerSocket httpd = new ServerSocket(5776, 10, InetAddress.getByName("192.168.210.122"));
}
catch (IOException ex) {
System.err.println(ex);
}
IOException
(again, really a BindException
) if the socket cannot be created and bound to the requested port or network interface.
public ServerSocket( ) throws IOException // Java 1.4
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
ServerSocket ss = new ServerSocket( );
// set socket options...
SocketAddress http = new InetSocketAddress(80);
ss.bind(http);
SocketAddress
to select an arbitrary port. This is like passing 0 for the port number in the other constructors.Accepting and Closing Connections
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.
public Socket accept( ) throws IOException
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( );
}
accept( )
in a separate thread.
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. 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
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.
kill
command (kill
pid
)
.
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
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.
public void close( ) throws IOException
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
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
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( );
}
The get Methods
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.
public InetAddress getInetAddress( )
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( );
ServerSocket
has not yet bound to a network interface, this method returns null.
public int getLocalPort( )
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);
}
}
}
D:\JAVA\JNP3\examples\10>java RandomPort
This server runs on port 1154
D:\JAVA\JNP3\examples\10>java RandomPort
This server runs on port 1155
D:\JAVA\JNP3\examples\10>java RandomPort
This server runs on port 1156
ServerSocket
has not yet bound to a port, then this method returns -1.Socket Options
SO_TIMEOUT
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
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);
}
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." );
}
}
SO_REUSEADDR // Java 1.4
public void setReuseAddress(boolean on) throws SocketException public boolean getReuseAddress( ) throws SocketException
ServerSocket
and then calling getReuseAddress( )
:
ServerSocket ss = new ServerSocket(10240);
System.out.println("Reusable: " + ss.getReuseAddress( ));
SO_RCVBUF // Java 1.4
public void setReceiveBufferSize(int size) throws SocketException public int getReceiveBufferSize( ) throws SocketException
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));
//...
public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) // Java 1.5
setPerformancePreferences()
method:
public void setPerformancePreferences(int connectionTime, int latency,
int bandwidth)
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.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.
public String toString( )
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.Implementation
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 app programmers.
public static void setSocketFactory(SocketImplFactory factory) throws IOException
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
.
protected final void implAccept(Socket s) throws IOException
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;
}
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( );; // ...
}