A simple client application

2. Get the associated input and output streams from the socket. A socket has two associated streams: an InputStream , which is used for receiving information, and an OutputStream , which is used to send information. 3. Close the socket when youre done with it. Just as we closed streams, we need to close sockets. In fact, closing a stream associated with a socket will automatically close the socket as well. This last step may not seem crucial for a client application; while a socket does use a port a scarce operating-system resource, a typical client machine usually has plenty of spare ports. However, while a socket connection is open between a client and a server, the server is also allocating resources. Its always a good idea to let the server know when youre done so it can free up resources as soon as possible.

2.2.1.1 A simple client application

The steps weve just seen are illustrated in the WebBrowser application, as shown in Exam ple 2- 1 . WebBrowser is an application that attempts to fetch the main web page from a designated machine. WebBrowser s main method is defined in the c om.ora.rmibook.chapter2.WebBrowser class. Example 2-1. The WebBrowser application public class WebBrowserFrame extends ExitingFrame { .... private void askForPageSocket webServer throws IOException { BufferedWriter request; request = new BufferedWriternew OutputStreamWriterwebServer. getOutputStream ; request.writeGET HTTP1.0\n\n; request.flush ; } private void receivePageSocket webServer throws IOException { BufferedReader webPage=null; webPage = new BufferedReadernew InputStreamReaderwebServer.getInputStream ; String nextLine; while null=nextLine=webPage.readLine { _displayArea.appendnextLine + \n; inefficient string handling } webPage.close ; return; } private class FetchURL extends AbstractAction { public FetchURL { putValueAction.NAME, Fetch; putValueAction.SHORT_DESCRIPTION, Retrieve the indicated URL; } public void actionPerformedActionEvent e { String url = _url.getText ; Socket webServer; try { webServer = new Socketurl, 80; } catch Exception invalidURL { _displayArea.setTextURL + url + is not valid.; return; } try { askForPagewebServer; receivePagewebServer; webServer.close ; } catch IOException whoReallyCares { _displayArea.append\n Error in talking to the web server.; } } } } Visually, WebBrowser is quite simple; it displays a JTextArea , a JTextField , and a JButton . The user enters an address in the text field and clicks on the button. The application then attempts to connect to port 80 [ 3] of the specified machine and retrieve the default web page. A screen shot of the application before the button is pressed is shown in Figur e 2- 1 . [ 3] Port 80 is an example of a well-known port. It is usually reserved for web servers and most web sites use it. Figure 2-1. The WebBrowser application before fetching a web page The WebBrowser application is implemented as a single subclass of JFrame . The socket-related code is contained in the Fetch buttons ActionListener and in the two private methods askForPage and receivePage . If all goes well, and no exceptions are thrown, the following code is executed when the button is clicked: String url = _url.getText ; Socket webServer = new Socketurl, 80; askForPagewebServer; receivePagewebServer; That is, the program assumes that the text field contains a valid address of a computer on which a web server runs. The program also assumes that the web server is listening for connections on port 80. Using this information, the program opens a socket to the web server, asks for a page, and receives a response. After displaying the response, the program closes the socket and waits for more input. Where did the number 80 come from? Recall that in order to create a socket connection, you need to have a machine address and a port. This leads to a boot-strapping problem™ in order to establish a socket connection to a server, you need the precise address. But you really want to avoid hardwiring server locations into a client application. One solution is to require the server machine to be specified at run-time and use a well-known port. There are a variety of common services that vend themselves on well-known ports. Web servers usually use port 80; SMTP the Internet mail protocol uses port 25; the RMI registry, which we will discuss later, uses port 1099. Another solution, which RMI uses, is to have clients ask a dedicated server which machine and port they can use to communicate with a particular server. This dedicated server is often known as a naming service. The code for asking and receiving pages is straightforward as well. In order to make a request, the following code is executed: private void askForPageSocket webServer throws IOException { BufferedWriter request; request = new BufferedWriternew OutputStreamWriterwebServer.getOutputStream ; request.writeGET HTTP1.0\n\n; request.flush ; } This acquires the sockets associated OutputStream , wraps a formatting object an instance of BufferedWriter around it, and sends a request. Similarly, receivePage gets the associated InputStream , and reads data from it: private void receivePageSocket webServer throws IOException { BufferedReader webPage=null; webPage = new BufferedReadernew InputStreamReaderwebServer.getInputStream ; String nextLine; while null=nextLine=webPage.readLine { _displayArea.appendnextLine + \n; inefficient string handling } return; }

2.2.2 Protocols and Metadata