Server Sockets in Java  Hot PDF Print E-mail
Tag it:
Delicious
Furl it!
Digg
NewsVine
Reddit
YahooMyWeb
Technorati
Articles Reviews Java
Written by Phil Harrison   
Wednesday, 24 January 2007

{mos_sb_discuss:34}

From a programmer’s point of view, the main difference between a client and a server has to do with initiation. A client always gets to assume that a server is available.


You can see this assumption at work when you construct a Socket instance: the constructor automatically connects to the specified server’s specified port.

 

A server, on the other hand, makes itself available and then waits for clients to initiate connections. This is done with an abstraction called a server socket , which in Java is represented by the java.net.ServerSocket class. The most useful form of the ServerSocket constructor is

public ServerSocket(int portNumber)

The constructor throws IOException if it gets into trouble. To make the new object available for client connections, call its accept() method, which returns an instance of Socket , as shown below:

try {
ServerSocket ss = new ServerSocket(1234);
Socket sock = ss.accept();
. . .
}
catch (IOException x) {
System.out.println(“Stress: “ + x.getMessage());
}


There is no way to know how long the accept() call will take. It depends on how promptly a client wants to take advantage of the service that the code just made available on port 1234 of server mangfalo.

Once a client connects, the accept() method constructs and returns an instance of Socket. The subsequent server code can use the socket’s input and output streams directly for byte communication, or higher-level streams can be chained to support communication of higher-level data. Thus, once a client has connected to the server, writing server code is just like writing client code.

Using sockets is a bit like using telephones in the following sense. At first the situation is asymmetrical. One person (analogous to the server) is hanging out at home, willing to communicate but not paying much attention to the phone. Another person (corresponding to the client), initiates a dialog by dialing their phone.

The “server’s” phone rings. The moment the “server” picks up the ringing phone, the two people are in identical situations, communicating with identical equipment.

Similarly, server and client code starts out looking different: the server constructs a ServerSocket and calls
accept() , while the client constructs a Socket. However, once the connection is established, both sides use identical equipment (a socket and its streams) to communicate.

When a ServerSocket instance executes an accept() call, the method blocks until a client connects. Blocking is an extremely important concept. A method blocks if, when realizing that a necessary resource is unavailable, the method gives up the processor until the resource becomes available.

In the case of accept() , the necessary resource is the client. Clearly the method can’t proceed until a client appears. In Java, methods block by calling wait() , which puts the current thread in a waiting state as you saw in Chapter 7, “Threads.” In a properly designed program, another thread will eventually detect the presence of the desired resource; that thread will notify the waiting thread.

TCP allows multiple clients to be connected to a single port on a server. (On a popular web or mail server, the number of clients on a port at any moment can be quite large.) Often the most sensible thing for a server to do after accept() returns is to create a new thread to deal with the new client, leaving the current thread free to accept more client connections.

For example, a server might rely on a class called ServiceGiver , which implements java.lang.Runnable .
The class’ constructor can store a socket on which communication is to take place, for which the run()
method provides the communication:

import java.net.*;
import java.io.*;

class ServiceGiver implements Runnable {
private Socket sock;

ServiceGiver(Socket sock) {
this.sock = sock;
}

public void run() {
try {
OutputStream ostr = sock.getOutputStream();
InputStream istr = sock.getInputStream();
// Do something with the streams.
. . .
}

catch (IOException x) {
System.out.println(“Stress: “ + x.getMessage());
}
}
}

A server can use the ServiceGiver class like this:

try {
ServerSocket ss = new ServerSocket(1234);
while (true) {
Socket sock = ss.accept();
ServiceGiver sg = new ServiceGiver(sock);
(new Thread(sg)).start();
}
}
catch (IOException x) {
System.out.println(“Stress: “ + x.getMessage());
}

The thread that calls accept() is almost always waiting for new client connections; it is unavailable only for the brief time required to pass a newly connected socket to a ServiceGiver instance.


User reviews

There are no user reviews for this item.

Add new review




Powered by jReviews

Last Updated ( Wednesday, 13 June 2007 )
 
< Prev   Next >