In "Read and write data with Java's I/O streams," we started to explore the input/output (I/O) classes, interfaces, and operations provided by the Java platform. Now, we'll continue our exploration of the I/O facilities provided by the Java platform by showing how the same techniques, classes, and data types used for reading and writing data to local file systems can be used when reading and writing data across remote connections.
A computer is typically endowed with one physical connection through which all data that's destined for it must enter. The problem with this is that many types of data, transported using many different protocols, must use this one physical connection, often at the same time. So does the poor digital device handle this predicament? Using a concept known as ports, the crafty little machine exposes a facade to the outside world that gives the impression that it is actually endowed with a limitless number of physical connections.
A port is simply a number that a computer system uses to route data to the appropriate application. Some port numbers, called well-known ports, are reserved for special services such as HTTP, FTP, and SMTP. Well-known port numbers range from 0 to 1023. The port number, along with information identifying that destination computer, accompanies data when it is transmitted across a network connection. This phenomenon opens application communications up to all kinds of possibilities, including hackers, but we'll leave that discussion for another time.
Java network applications, broadly speaking, are concerned with two types of communications, TCP (connection-based) and UDP (connectionless). In connection-based communications, an application associates/binds endpoints known as sockets to specific port numbers. This effectively directs the system to route all data intended for an application to a specified port. In connectionless communications, individual packets containing a port number are broadcasted to the intended targets.
All of this techie talk can quickly turn into a lot of mumbo-jumbo. Fortunately for us, Java has provided the java.net package. Classes and interfaces within this package provide a unified set of abstractions for applications to use for network communications.
The java.net package
The java.net package exposed by the Java platform provides a class, Socket, that represents one connection in a multiconnection conversation between one Java program and another. The Socket class hides the nasty details of each particular native system from a Java program. The java.net.Socket class allows Java programs to communicate over a network in a platform-agnostic manner. Additionally, the java.net package provides a class, ServerSocket, that represents a connection that server-oriented applications use to accept incoming connections from client applications.
The java.net package provides classes and interfaces for writing programs that use either TCP or UDP. Applications communicating with TCP use the URL, URLConnection, Socket, and ServerSocket classes. Applications communicating with UDP use the DatagramPacket, DatagramSocket, and MulticastSocket classes.
Reading and writing to sockets
Java programs that use the socket classes from the java.net package must initialize the connections they want to communicate over. Then, data must be written to and read from the connection. To read and write data to a socket connection, we obtain an output or input stream from the socket and then read and write to these streams in a manner similar to the techniques we used to write to a file located on a local file system.
TCP client and server
Let's look at a simple example that demonstrates this interaction of connections and data streams. The code is shown in Listing A. The program implements a client class, TCPClient, that connects to the server class, TCPServer. The server receives data from the client, writes the data to System.out, and then sends acknowledgment back to the client.
The server opens a socket on port 7776 and then waits for a client to connect. Once a client has successfully connected, the server will open the input stream and the output stream on the client socket to read and write data. Notice how we use streams and readers in much the same way we do to write to a local file system.
The client (see Listing B) will attempt to create a socket on port 7776 that connects to the server. If the attempt to connect succeeds, the client will read data entered by the user and then write that data to the server using the output stream provided by the socket. The client program will read the data passed back from the server and display it to System.out.
The networking classes provided by the Java platform enable us to implement applications that communicate across a network/remote connection. Using Java's socket classes, we can communicate between two or more clients and/or servers.
In our next article, we'll extend our discussion of Java's networking framework into the realm of the Internet and URLs. We'll also look at how we can use the same data transfer mechanisms to read and write data over URL connections.