Working with Sockets

   

Sockets are a programming abstraction that isolates your code from the low-level implementations of the TCP/IP protocol stack. TCP sockets enable you to quickly develop your own custom client/server applications. Although the URL classes described later in this chapter are useful with well-established protocols, sockets allow you to develop your own modes of communication.

Sockets, as a programming interface, were originally developed at the University of California at Berkeley as a tool to easily accomplish network programming. Originally part of UNIX operating systems, the concept of sockets has been incorporated into a wide variety of operating environments, including Java.

What Is a Socket?

A socket is a handle to a communications link over the network with another application. A TCP socket uses the TCP protocol, inheriting the behavior of that transport protocol. Four pieces of information are needed to create a TCP socket:

  • The local system's IP address

  • The TCP port number the local application is using

  • The remote system's IP address

  • The TCP port number to which the remote application is responding

The original TCP specification, RFC 793, used the term socket to mean the combination of a system's IP address and port number. A pair of sockets identified a unique end-to-end TCP connection. In this discussion, the term socket is used at a higher level, and a socket is your interface to a single network connection.

Sockets are often used in client/server applications. A centralized service waits for various remote machines to request specific resources, handling each request as it arrives. For clients to know how to communicate with the server, standard application protocols are assigned well-known ports. On UNIX operating systems, ports below 1,024 can only be bound by applications with super- user (for example, root) privileges; thus, for control, these well-known ports lie within this range by convention. Some well-known ports are shown in Table 23.1.

Table 23.1. Well-Known TCP Ports and Services
Port Service
7 Echo Server
21 FTP
23 Telnet
25 SMTP (Standard Mail Transfer Protocol)
79 Finger
80 HTTP

For many application protocols, you can merely use the Telnet application to connect to the service port and then manually emulate a client. This might help you understand how client/server communications work.

Client applications must also obtain, or bind, a port to establish a socket connection. Because the client initiates the communication with the server, such a port number could conveniently be assigned at runtime. Client applications are usually run by normal, unprivileged users on UNIX systems, and thus these ports are allocated from the range above 1,024. This convention has held when migrated to other operating systems, and client applications are generally given a dynamically allocated or ephemeral port above 1,024.

Because no two applications can bind the same port on the same machine simultaneously , a socket uniquely identifies a communications link. Realize that a server can respond to two clients on the same port, because the clients will be on different systems and/or different ports; the uniqueness of the link's characteristics are preserved. Figure 23.3 illustrates this concept.

Figure 23.3. Many clients can connect to a single server through separate sockets.

graphics/23fig03.gif

Figure 23.3 shows a server application responding to three sockets through port 80, the well-known port for HTTP. Two sockets are communicating with the same remote machine, although the third is to a separate system. Note the unique combination of the four TCP socket characteristics.

Figure 23.3 also shows a simplified view of a client-server connection. Many machines are configured with multiple IP interfaces ”they have more than one IP address. These distinct IP addresses allow for separate connections to be maintained . Thus, a server might have an application accept connections on port 80 for one IP address while a different application handles connections to port 80 for another IP address. These connections are distinct. The Java socket classes, described within the next section, "Java TCP Socket Classes," allow you to select a specific local interface for the connection.

Java has a number of classes that allow you to create socket-based network applications. The two classes you use include java.net.Socket and java.net.ServerSocket. The Socket class acts as one-side in machine-to-machine connection. There is a socket on each side of the connection. The ServerSocket class waits for connections from client Socket's and then communicates to that Socket using a different client Socket. That's the second socket in a machine-to-machine communication. Don't worry if you are still confused . It will become more apparent shortly.

Client Sockets

As stated previously, the Socket class is used for normal two-way socket communications. The actual work of the Socket class is performed by an instance of the SocketImpl class. By changing the implementation class for the Socket, an application can change the behavior of the underlying communication. This might be necessary for an application that needs to communicate through a company firewall.

There are several constructors for the Socket class. They differ in the number and type of parameters each one takes. There's also one that takes a SocketImpl as a parameter to use a user-defined implementation rather than the default behavior. To get started, take a look at an example.

The Socket class has methods that allow you to read and write through the socket getInputStream and getOutputStream methods. To make applications simpler to design, the streams these methods return are usually decorated by another java.io object, such as BufferedReader or PrintWriter, respectively. Both getInputStream and getOutputStream throw an IOException, which should be caught. Here's an example that uses the Socket class. Listing 23.1 shows a client program that connects to an echo server running somewhere on the Internet. An echo server is a program that after a client is connected, just sends back exactly the text that is sent to it. Echo servers usually listen on port 7.

Note

You might have to find a different host to run this example if the one listing in the source no longer supports an echo server. You can find some by searching on the Internet, or just try some well-known sites. Usually, most educational institutions have an echo server running. You can change the host for this example by modifying the static final variables listed at the top of the source code.


Listing 23.1 Source Code for EchoClientExample.java
 import java.net.*; import java.io.*; public class EchoClientExample {   public static final String HOST = "www.gatech.edu";   public static final int PORT = 7;   // Default Constructor   public EchoClientExample()   {     super();   }   public void testEcho()   {     try     {       // Get connected to an echo server somewhere, they are usually on       // port 7 of a well known server       Socket socket = new Socket(HOST, PORT);       // Create a reader and stream for reading the data from the echo server       BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));       // Create a writer and stream for writing to the echo server       PrintWriter output = new PrintWriter(socket.getOutputStream(), true);       // Send some text to the echo server       System.out.println("Sending Hello to the echo server");       output.println("Hello");       // Get the message from the echo server       System.out.println(input.readLine() + " from the echo server");       // Close the socket       socket.close();     }     catch(UnknownHostException ex)     {       System.err.println("Unknown host: " + ex);       System.exit(1);     }     catch(IOException excpt)     {       System.err.println("Failed I/O: " + excpt);       System.exit(1);     }   }     public static void main(String[] args)     {       EchoClientExample example = new EchoClientExample();       example.testEcho();     } } 

Listing 23.2 shows the output generated from the EchoClientExample program.

Listing 23.2 Output for EchoClientExample.java
 C:\jdk1.3se_book\classes>java EchoClientExample Sending Hello to the echo server Hello from the echo server C:\jdk1.3se_book\classes> 

Troubleshooting Tip

If you are trying to connect using a socket and are having trouble, see "Can't Connect to a Socket" in the "Troubleshooting" section at the end of this chapter.


Remember to close the Socket class when you are finished using it. You will also want to close any input or output streams that you have opened to use with the Socket.

Server Sockets

There's nothing special about the program in Listing 23.1. Using the Socket class is just that easy. The Socket class is really only half of it. What if you wanted to support an echo server on your site? An echo server, as its name implies, is a server program. The Socket class is used by clients, whereas the ServerSocket is to be used for TCP server programs.

The basic function of a ServerSocket is to listen and wait for a client Socket to establish a connection and then create a separate Socket instance on the server side to handle the connection with the client. After the ServerSocket handles the hand shaking with the client and a connection is established, the ServerSocket goes back to listening for other clients to connect.

As mentioned before, the actual work of both the Socket and the ServerSocket classes is performed by a class called SocketImpl and its subclasses. The SocketImpl class is abstract and is provided by a vendor. By default, you use the standard Sun implementation of the SocketImpl class. You can however change out the SocketImpl implementation, which acts as a socket factory, to tunnel or go through a local firewall for example. In most cases, you'll want to stick with the default implementation.

ServerSocket has three constructors:

 public ServerSocket(int port) throws IOException; public ServerSocket(int port, int backlog) throws IOException; public ServerSocket(int port, int backlog, InetAddress localAddr) throws IOException; 

The first constructor creates a listening socket at the port specified, allowing for the default number of 50 clients waiting in the connection queue. The second constructor enables you to change the length of the connection queue, allowing greater or fewer clients to wait to be processed by the server. In either case, if the number of clients requesting a connection exceeds the queue size , the connection will be refused .

The final constructor allows you to specify a local interface to listen for connections. This is in case your machine has multiple IP addresses, this constructor allows you to provide services to specific IP addresses. Should you use the first two constructors on such a machine, the ServerSocket will accept connections to any of the machine's IP addresses.

Note

If you specify a port value of 0 in any three of the constructors, a Socket is created on any free port that the server selects.


Remember to close the Socket class when you are finished using it. You will also want to close any input or output streams that you have opened.

After creating a ServerSocket, the accept method can be used to wait for a client to connect. The accept method blocks until a client connects, and then returns a Socket instance for communicating to the client. Blocking is a programming term that means a routine enters an internal loop indefinitely, returning only when a specific condition occurs. The condition in the case of the accept method is that a client attempts to make a connection. When a client requests a connection to the server program, the accept method will unblock and continue executing the program.

The application in Listing 23.3 creates a ServerSocket at port 7, waits for client connections, and then opens streams through which communication can take place after a client connects. The server will just echo any text that is sent to it. This example is simplistic, but this is basically what an echo server does.

Listing 23.3 Source Code for EchoServer.java
 import java.net.*; import java.io.*; public class EchoServer {   public static final int PORT = 7;   // Default Constructor   public EchoServer()   {     super();   }   public void startEcho()   {     try     {       // Create a Server Socket on the       ServerSocket server = new ServerSocket(PORT);       // Wait for a single client to connect       System.out.println("Waiting on a client to connect");       Socket clientSocket = server.accept();       System.out.println("Client requested a connection to the echo server");       BufferedReader input =          new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));       PrintWriter output =            new PrintWriter(clientSocket.getOutputStream(), true);       // Get the data from the client       String msg = input.readLine();       System.out.println("Client sent " + msg);       // Send the data back to the client       output.println(msg);       System.out.println("echo server exiting");       clientSocket.close();     }     catch(IOException ex)     {       System.err.println("Failed I/O: " + ex);       System.exit(1);     }   }   public static void main(String[] args)   {     EchoServer echoServer = new EchoServer();     echoServer.startEcho();   } } 

You can use the EchoClientExample from Listing 23.1 to test this EchoServer example. You will just need to change the HOST value at the top of the EchoClientExample source code. You can change it to localhost, which is your machine where the EchoServer program should be listening.

The example in Listing 23.2 only handles a single client and exits after the client sends some initial data, but you can add some looping and change the manner in which the server program handles the client to almost make this a full-fledged echo server program. To handle the client Socket properly, you would probably want to create a ClientHandler class that extends Thread and just echoes back everything the client sends until the client exists. This would be very easy to write.

Note

The socket classes in the Java API provide a convenient stream interface by using your host's TCP implementation. Within the SDK, a subclass of the abstract class SocketImpl performs the interaction with your machine's TCP. It is possible to define a new SocketImpl that could use a different transport layer than plain TCP. You can change this transport layer implementation by creating your own subclass of SocketImpl and defining your own SocketImplFactory. However, in this chapter, it is assumed that you are using the SDK socket implementation, which uses TCP.


   


Special Edition Using Java 2 Standard Edition
Special Edition Using Java 2, Standard Edition (Special Edition Using...)
ISBN: 0789724685
EAN: 2147483647
Year: 1999
Pages: 353

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