4.11. Networking
The java.net package defines a number of
classes that make writing networked applications surprisingly easy. The easiest class to use is
URL, which represents a uniform resource
locator. Different Java implementations may support different
sets of URL protocols, but, at a minimum, you can rely on support
for the http:, ftp:, and
file: protocols. Here are some ways you can
use the URL class:
import java.net.*;
import java.io.*;
// Create some URL objects
URL url=null, url2=null, url3=null;
try {
url = new URL("http://www.oreilly.com"); // An absolute URL
url2 = new URL(url, "catalog/books/javanut3/"); // A relative URL
url3 = new URL("http:", "www.oreilly.com", "index.html");
} catch (MalformedURLException e) { /* Ignore this exception */ }
// Read the content of a URL from an input stream:
InputStream in = url.openStream();
// For more control over the reading process, get a URLConnection object
URLConnection conn = url.openConnection();
// Now get some information about the URL
String type = conn.getContentType();
String encoding = conn.getContentEncoding();
java.util.Date lastModified = new java.util.Date(conn.getLastModified());
int len = conn.getContentLength();
// If necessary, read the contents of the URL using this stream
InputStream in = conn.getInputStream();
Sometimes you need more control over your networked application
than is possible with the URL class. In this
case, you can use a Socket to communicate
directly with a server. For example:
import java.net.*;
import java.io.*;
// Here's a simple client program that connects to a web server,
// requests a document, and reads the document from the server.
String hostname = "java.oreilly.com"; // The server to connect to
int port = 80; // Standard port for HTTP
String filename = "/index.html"; // The file to read from the server
Socket s = new Socket(hostname, port); // Connect to the server
// Get I/O streams we can use to talk to the server
InputStream sin = s.getInputStream();
BufferedReader fromServer = new BufferedReader(new InputStreamReader(sin));
OutputStream sout = s.getOutputStream();
PrintWriter toServer = new PrintWriter(new OutputStreamWriter(sout));
// Request the file from the server, using the HTTP protocol
toServer.print("GET " + filename + " HTTP/1.0\n\n");
toServer.flush();
// Now read the server's response, assume it is a text file, and print it out
for(String l = null; (l = fromServer.readLine()) != null; )
System.out.println(l);
// Close everything down when we're done
toServer.close();
fromServer.close();
s.close();
A client application uses a Socket to
communicate with a server. The server does the same thing: it
uses a Socket object to communicate with each
of its clients. However, the server has an additional task, in
that it must be able to recognize and accept client connection requests. This is done with the ServerSocket class. The
following code shows how you might use a ServerSocket. The code
implements a simple HTTP server that responds to all requests by
sending back (or mirroring) the exact contents of the HTTP
request. A dummy server like this is useful when debugging HTTP clients:
import java.io.*;
import java.net.*;
public class HttpMirror {
public static void main(String[] args) {
try {
int port = Integer.parseInt(args[0]); // The port to listen on
ServerSocket ss = new ServerSocket(port); // Create a socket to listen
for(;;) { // Loop forever
Socket client = ss.accept(); // Wait for a connection
ClientThread t = new ClientThread(client); // A thread to handle it
t.start(); // Start the thread running
} // Loop again
}
catch (Exception e) {
System.err.println(e.getMessage());
System.err.println("Usage: java HttpMirror <port>");
}
}
static class ClientThread extends Thread {
Socket client;
ClientThread(Socket client) { this.client = client; }
public void run() {
try {
// Get streams to talk to the client
BufferedReader in =
new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter out =
new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
// Send an HTTP response header to the client
out.print("HTTP/1.0 200\nContent-Type: text/plain\n\n");
// Read the HTTP request from the client and send it right back
// Stop when we read the blank line from the client that marks
// the end of the request and its headers.
String line;
while((line = in.readLine()) != null) {
if (line.length() == 0) break;
out.println(line);
}
out.close();
in.close();
client.close();
}
catch (IOException e) { /* Ignore exceptions */ }
}
}
}
Note how elegantly both the URL and
Socket classes use the
input/output streams that we saw earlier in the chapter. This is
one of the features that makes the Java networking classes so
powerful.
Both URL and
Socket perform networking on top of a
stream-based network connection. Setting up and maintaining a
stream across a network takes work at the network level, however. Sometimes you need a low-level way to speed a packet of data
across a network, but you don't care about maintaining a stream. If, in addition, you don't need a guarantee that your data
will get there or that the packets of data will arrive in the
order you sent them, you may be interested in the
DatagramSocket and
DatagramPacket classes:
import java.net.*;
// Send a message to another computer via a datagram
try {
String hostname = "host.domain.org"; // The computer to send the data to
InetAddress address = // Convert the DNS hostname
InetAddress.getByName(hostname); // to a lower-level IP address.
int port = 1234; // The port to connect to
String message = "The eagle has landed."; // The message to send
byte[] data = message.getBytes(); // Convert string to bytes
DatagramSocket s = new DatagramSocket(); // Socket to send message with
DatagramPacket p = // Create the packet to send
new DatagramPacket(data, data.length, address, port);
s.send(p); // Now send it!
s.close(); // Always close sockets when done
}
catch (UnknownHostException e) {} // Thrown by InetAddress.getByName()
catch (SocketException e) {} // Thrown by new DatagramSocket()
catch (java.io.IOException e) {} // Thrown by DatagramSocket.send()
// Here's how the other computer can receive the datagram
try {
byte[] buffer = new byte[4096]; // Buffer to hold data
DatagramSocket s = new DatagramSocket(1234); // Socket to receive it through
DatagramPacket p =
new DatagramPacket(buffer, buffer.length); // The packet to receive it
s.receive(p); // Wait for a packet to arrive
String msg = // Convert the bytes from the
new String(buffer, 0, p.getLength()); // packet back to a string.
s.close(); // Always close the socket
}
catch (SocketException e) {} // Thrown by new DatagramSocket()
catch (java.io.IOException e) {} // Thrown by DatagramSocket.receive()
 |  |  |
| 4.10. Input and Output Streams |  | 4.12. Processes |

Copyright © 2001 O'Reilly & Associates. All rights reserved.
|