Networking is tightly integrated in Java. Socket-based communication is provided that enables programs to communicate through designated sockets. Sockets are the endpoints of logical connections between two hosts and can be used to send and receive data. Java treats socket communications much as it treats I/O operations; thus programs can read from or write to sockets as easily as they can read from or write to files.
Network programming usually involves a server and one or more clients . The client sends requests to the server, and the server responds to the requests . The client begins by attempting to establish a connection to the server. The server can accept or deny the connection. Once a connection is established, the client and the server communicate through sockets.
The server must be running when a client starts. The server waits for a connection request from a client. The statements needed to create a server and a client are shown in Figure 25.1.
To establish a server, you need to create a server socket and attach it to a port, which is where the server listens for connections. The port identifies the TCP service on the socket. Port numbers range from 0 to 65536, but port numbers 0 to 1024 are reserved for privileged services. For instance, the email server runs on port 25, and the Web server usually runs on port 80.
You can choose any port number that is not currently used by any other process. The following statement creates a server socket serverSocket :
ServerSocket serverSocket = new ServerSocket(port);
Note
Attempting to create a server socket on a port already in use would cause the java.net.BindException . |
After a server socket is created, the server can use the following statement to listen for connections:
Socket socket = serverSocket.accept();
This statement waits until a client connects to the server socket. The client issues the following statement to request a connection to a server:
Socket socket = new Socket( serverName, port );
This statement opens a socket so that the client program can communicate with the server. serverName is the server's Internet host name or IP address. The following statement creates a socket at port 8000 on the client machine to connect to the host 130.254.204.36 :
Socket socket = new Socket( "130.254.204.36" , 8000 )
Alternatively, you can use the domain name to create a socket, as follows :
Socket socket = new Socket( "drake.armstrong.edu" , 8000 );
When you create a socket with a host name, the JVM asks the DNS to translate the host name into the IP address.
Note
A program can use the host name localhost or the IP address 127.0.0.1 to refer to the machine on which a client is running. |
Note
The Socket constructor throws a java.net.UnknownHostException if the host cannot be found. |
After the server accepts the connection, communication between server and client is conducted the same as for I/O streams. The statements needed to create the streams and to exchange data between them are shown in Figure 25.2.
To get an input stream and an output stream, use the getInputStream() and getOutputStream() methods on a socket object. For example, the following statements create an InputStream stream called input and an OutputStream stream called output from a socket:
InputStream input = socket.getInputStream(); OutputStream output = socket.getOutputStream();
The InputStream and OutputStream streams are used to read or write bytes. You can use DataInputStream , DataOutputStream , BufferedReader , and PrintWriter to wrap on the InputStream and OutputStream to read or write data, such as int , double , or String . The following statements, for instance, create a DataInputStream stream, input , and a DataOutput stream, output , to read and write primitive data values:
DataInputStream input = new DataInputStream (socket.getInputStream()); DataOutputStream output = new DataOutputStream (socket.getOutputStream());
The server can use input.readDouble() to receive a double value from the client, and output.writeDouble(d) to send double value d to the client.
Tip
Recall that binary I/O is more efficient than text I/O because text I/O requires encoding and decoding. Therefore it is better to use binary I/O for transmitting data between a server and a client to improve performance. |
This example presents a client program and a server program. The client sends data to a server. The server receives the data, uses it to produce a result, and then sends the result back to the client. The client displays the result on the console. In this example, the data sent from the client comprises the radius of a circle, and the result produced by the server is the area of the circle (see Figure 25.3).
The client sends the radius through a DataOutputStream on the output stream socket, and the server receives the radius through the DataInputStream on the input stream socket, as shown in Figure 25.4(a). The server computes the area and sends it to the client through a DataOutputStream on the output stream socket, and the client receives the area through a DataInputStream on the input stream socket, as shown in Figure 25.4(b). The server and client programs are given in Listings 25.1 and 25.2. Figure 25.5 contains a sample run of the server and the client.
1 import java.io.*; 2 import java.net.*; 3 import java.util.*; 4 import java.awt.*; 5 import javax.swing.*; 6 7 public class Server extends JFrame { 8 // Text area for displaying contents 9 private JTextArea jta = new JTextArea(); 10 11 public static void main(String[] args) { 12 new Server(); 13 } 14 15 public Server() { 16 // Place text area on the frame 17 setLayout( new BorderLayout()); 18 add( new JScrollPane(jta), BorderLayout.CENTER); 19 20 setTitle( "Server" ); 21 setSize( 500 , 300 ); 22 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 23 setVisible( true ); // It is necessary to show the frame here! 24 25 try { 26 // Create a server socket 27 ServerSocket serverSocket = new ServerSocket( 8000 ); 28 jta.append( "Server started at " + new Date() + '\n' ); 29 30 // Listen for a connection request 31 Socket socket = serverSocket.accept(); 32 33 // Create data input and output streams 34 DataInputStream inputFromClient = new DataInputStream( 35 socket.getInputStream()); 36 DataOutputStream outputToClient = new DataOutputStream( 37 socket.getOutputStream()); 38 39 while ( true ) { 40 // Receive radius from the client 41 double radius = inputFromClient.readDouble(); 42 43 // Compute area 44 double area = radius * radius * Math.PI; 45 46 // Send area back to the client 47 outputToClient.writeDouble(area); 48 49 jta.append( "Radius received from client: " + radius + '\n' ); 50 jta.append( "Area found: " + area + '\n' ); 51 } 52 } 53 catch (IOException ex) { 54 System.err.println(ex); 55 } 56 } 57 } |
1 import java.io.*; 2 import java.net.*; 3 import java.awt.*; 4 import java.awt.event.*; 5 import javax.swing.*; 6 7 public class Client extends JFrame { 8 // Text field for receiving radius 9 private JTextField jtf = new JTextField(); 10 11 // Text area to display contents 12 private JTextArea jta = new JTextArea(); 13 14 // IO streams 15 private DataOutputStream toServer; 16 private DataInputStream fromServer; 17 18 public static void main(String[] args) { 19 new Client(); 20 } 21 22 public Client() { 23 // Panel p to hold the label and text field 24 JPanel p = new JPanel(); 25 p.setLayout( new BorderLayout()); 26 p.add( new JLabel( "Enter radius" ), BorderLayout.WEST); 27 p.add(jtf, BorderLayout.CENTER); 28 jtf.setHorizontalAlignment(JTextField.RIGHT); 29 30 setLayout( new BorderLayout()); 31 add(p, BorderLayout.NORTH); 32 add( new JScrollPane(jta), BorderLayout.CENTER); 33 34 jtf.addActionListener( new ButtonListener()); // Register listener 35 36 setTitle( "Client" ); 37 setSize( 500 , 300 ); 38 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 39 setVisible( true ); // It is necessary to show the frame here! 40 41 try { 42 // Create a socket to connect to the server 43 Socket socket = new Socket( "localhost" , 8000 ); 44 // Socket socket = new Socket("130.254.204.36", 8000); 45 // Socket socket = new Socket("drake.Armstrong.edu", 8000); 46 47 // Create an input stream to receive data from the server 48 fromServer = new DataInputStream( 49 socket.getInputStream()); 50 51 // Create an output stream to send data to the server 52 toServer = 53 new DataOutputStream(socket.getOutputStream()); 54 } 55 catch (IOException ex) { 56 jta.append(ex.toString() + '\n' ); 57 } 58 } 59 60 private class ButtonListener implements ActionListener { 61 public void actionPerformed(ActionEvent e) { 62 try { 63 // Get the radius from the text field 64 double radius = Double.parseDouble(jtf.getText().trim()); 65 66 // Send the radius to the server 67 toServer.writeDouble(radius); 68 toServer.flush(); 69 70 // Get area from the server 71 double area = fromServer.readDouble() ; 72 73 // Display to the text area 74 jta.append( "Radius is " + radius + "\n" ); 75 jta.append( "Area received from the server is " 76 + area + '\n' ); 77 } 78 catch (IOException ex) { 79 System.err.println(ex); 80 } 81 } 82 } 83 } |
You start the server program first, then start the client program. In the client program, enter a radius in the text field and press Enter to send the radius to the server. The server computes the area and sends it back to the client. This process is repeated until one of the two programs terminates.
The networking classes are in the package java.net . This should be imported when writing Java network programs.
The Server class creates a ServerSocket serverSocket and attaches it to port 8000, using this statement (line 27 in Server.java):
ServerSocket serverSocket = new ServerSocket( 8000 );
The server then starts to listen for connection requests, using the following statement (line 31 in Server.java):
Socket socket = serverSocket.accept();
The server waits until a client requests a connection. After it is connected, the server reads the radius from the client through an input stream, computes the area, and sends the result to the client through an output stream.
The Client class uses the following statement to create a socket that will request a connection to the server on the same machine (localhost) at port 8000 (line 43 in Client.java):
Socket socket = new Socket( "localhost" , 8000 );
If you run the server and the client on different machines, replace localhost with the server machine's host name or IP address. In this example, the server and the client are running on the same machine.
If the server is not running, the client program terminates with a java.net.ConnectException . After it is connected, the client gets input and output streams ”wrapped by data input and output streams ”in order to receive and send data to the server.
If you receive a java.net.BindException when you start the server, the server port is currently in use. You need to terminate the process that is using the server port and then restart the server.
What happens if the setVisible(true) statement in line 23 in Server.java is moved after the try-catch block in line 56 in Server.java? The frame would not be displayed, because the while loop in the try-catch block will not finish until the program terminates.