Chapter 11
(such as the network is down, the server is busy, the server cannot be located, and so on). In network programming, it is important to pay extra attention to error-handling details, as communication problems aren’t just a possibility — they are pretty much guaranteed to happen at some point. Now that you have defined an address, you can create a new Socket class to attempt a connection:
Socket socket = new Socket();
socket.connect(address);
If the connection succeeds, either Java I/O classes or NIO (java.nio) classes can be used to send and receive data. In these examples, you will use normal Java I/O because it is often easier to understand and provides better code readability. Once the socket is connected, both InputStream and OutputStream objects from the java.io package can be retrieved and communication can begin:
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
These objects are often wrapped around other higher-level and easier to use I/O classes just as they are in normal Java I/O programming. Suppose, for example, that all the communication you are going to send and receive over the socket is textual data. Java provides the BufferedReader and PrintWriter objects that can be wrapped around the input and output stream objects:
PrintWriter out = new PrintWriter(out);
BufferedReader br = new BufferedReader(new InputStreamReader(in)); out.println(“Hello, remote computer”);
out.flush();
String serverResponse = br.readLine();
Note: The call to flush() in the preceding code segment is important. PrintWriter and other I/O classes buffer data before writing them to their underlying output stream. To have the send take place immediately, you flush the underlying output stream so the data you have written to the PrintWriter is immediately written to the underlying output stream, in this case, the OutputStream from the Socket, which then sends the data over the network. PrintWriter can also be created to automatically flush any output written straight to the underlying output stream, at the disadvantage of losing the ability to buffer data before it is sent to optimize network performance.
That’s really all there is to sockets. The difficult aspect of sockets comes when determining and implementing the protocol by which two different processes agree to communicate. In the “Implementing a Protocol” section, the difficulties will be explored, and a small portion of HTTP will be implemented.
Server Programming
Programming server-side sockets with Java is just as easy as on the client-side. The ServerSocket class is used to initiate a passive TCP connection. A passive TCP connection monitors a particular port on the host machine and waits for a remote client to connect. Once a connection is initiated by a client, the ServerSocket class dispatches a Socket class, which in turn can be used to get the input and output streams associated with the connection (as well as the hostname and address of the client machine). Certain ports on computers are generally associated with certain protocols, port 80 is HTTP, 23 is Telnet, 25 is SMTP, and so on. When picking a port to use for your application, the general rule of thumb is to keep it above 1000, as most common server applications do not use ports in this range. If a ServerSocket is created on a port that is already in use, an exception will be thrown, and the server