Chapter-3
Networking in Java
By the end of this chapter, you will be able:
• To explain terms: TCP, IP, domain name, domain name server, stream based
communications, and packet-based communications
• To create servers using server sockets and clients using client Sockets
• To implement Java networking programs using stream sockets
• To develop an example of a client/server application
• To obtain Internet addresses using the InetAddress class.
• To develop servers for multiple clients
1
Introduction
Computer networking is used to send and receive messages among computers on the
Internet.
When a computer needs to communicate with another computer, it needs to know the
other computer’s address.
An Internet Protocol (IP) address uniquely identifies the computer on the Internet.
An IP address consists of four dotted decimal numbers between 0 and 255, such as
[Link].
Since it is not easy to remember so many numbers, they are often mapped to
meaningful names called domain names, such as [Link]
Special servers called Domain Name Servers (DNS) on the Internet translate host
names into IP addresses.
When a computer contacts [Link] , it first asks the DNS to translate this
domain name into a numeric IP address and then sends the request using the IP
address. 2
The Internet Protocol is a low-level protocol for delivering data from one computer to
another across the Internet in packets.
Two higher-level protocols used in conjunction with the IP are the Transmission Control
Protocol (TCP) and the User Datagram Protocol (UDP).
TCP enables two hosts to establish a connection and exchange streams of data.
TCP guarantees delivery of data and also guarantees that packets will be delivered in
the same order in which they were sent.
UDP is a standard, low-overhead, connectionless, host-to-host protocol that is used over
the IP.
UDP allows an application program on one computer to send a datagram to an
application program on another computer.
Java supports both stream-based and packet-based communications.
Stream-based communications use TCP for data transmission, whereas packet-based
communications use UDP. 3
Since TCP can detect lost transmissions and resubmit them, transmissions are lossless
and reliable.
Stream-based communications are used in most areas of Java programming. UDP, in
contrast, cannot guarantee lossless transmission.
Client/Server Computing
Java provides the ServerSocket class for creating a server socket and the Socket
class for creating a client socket.
Two programs on the Internet communicate through a server socket and a client socket
using I/O streams.
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.
4
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.
TCP Sockets
Server Sockets
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 other programs. The
following statement creates a server socket serverSocket:
ServerSocket serverSocket = new ServerSocket(port); 5
Note
Attempting to create a server socket on a port already in use would cause a
[Link].
Client Sockets
After a server socket is created, the server can use the following statement to listen for
connections:
Socket socket = [Link]();
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 on the client machine to connect to the host
[Link] at port 8000:
Socket socket = new Socket("[Link]", 8000)
Alternatively, you can use the domain name to create a socket, as follows:
Socket socket = new Socket(“[Link] ", 8000);
6
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 [Link] to refer to
the machine on which a client is running.
The Socket constructor throws a [Link] if the host
cannot be found.
In general, as shown in the figure below, the server creates a server socket and, once a
connection to a client is established, connects to the client with a client socket.
7
After the server accepts the connection, communication between the server and the
client is conducted in the same way as for I/O streams.
The statements needed to create the streams and to exchange data between them are
shown in the following figure
8
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 = [Link]();
OutputStream output = [Link]();
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 the DataInputStream stream input
and the DataOutputStream stream output to read and write primitive data values:
DataInputStream input = new DataInputStream
([Link]());
DataOutputStream output = new DataOutputStream
([Link]());
9
The server can use [Link]() to receive a double value from the client
and [Link](d) to send the double value d to the client.
Tip
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.
A Client/Server Example
The client sends the radius to the server; the server computes the area and sends it to
the client as shown below.
(a) The client sends the radius to the server. (b) The server sends the area to the client.
10
//server code
import [Link].*;
import [Link].*;
import [Link].*;
public class ServerArea {
private static ServerSocket serverSocket;
private static int PORT=8000;
private static DataInputStream inputFromClient = null;
private static DataOutputStream outputToClient = null;
public static void main(String [] args){
[Link]("Opening port...\n");
try {
// Create a server socket
serverSocket = new ServerSocket(PORT);
[Link]("Server started at " + new Date() + '\n');
}
catch(IOException ioEx)
{
[Link]("Unable to attach to port!");
[Link](1);
}
11
do
{
handleClient();
}while (true);
}
private static void handleClient()
{
Socket link = null;
try{
// Listen for a connection request
link = [Link]();
// Create data input and output streams
inputFromClient = new DataInputStream([Link]());
outputToClient = new DataOutputStream([Link]());
int numRequest=0;
double radius = [Link]();
while (radius!=0) {
12
// Compute area
double area = radius * radius * [Link];
numRequest++;
// Send area back to the client
[Link](area);
[Link]("Request number : " + numRequest + '\n');
[Link]("Radius received from client: " + radius +
'\n');
[Link]("Area is: %.2f %s" , area , "\n");
// Receive radius from the client
radius = [Link]();
}
}
catch(IOException ex) {
//[Link]();
[Link]("Client disconnected");
}
finally{
try{
[Link]("Closing connection...");
[Link]();
13
}catch(IOException ioEx)
{
[Link]("Unable to disconnect!");
[Link](1);
}
}
}
}
14
//client code
import [Link].*;
import [Link].*;
import [Link];
public class ClientArea{
// IO streams
private static DataOutputStream toServer = null;
private static DataInputStream fromServer = null;
//Socket instance
private static Socket socket;
private static int PORT=8000;
private static String serverName="localhost";
private static Scanner in = new Scanner([Link]);
private static double radius;
private static double area;
public static void main(String []args){
[Link]("Client running");
accessServer();
}
15
public static void accessServer(){
try {
// Create a socket to connect to the server
socket = new Socket(serverName, PORT);
// Socket socket = new Socket("[Link]", 8000);
// Socket socket = new Socket(“[Link]", 8000);
// Create an input stream to receive data from the server
fromServer = new DataInputStream([Link]());
// Create an output stream to send data to the server
toServer = new DataOutputStream([Link]());
[Link]("Enter a radius [0 to quit]: ");
radius = [Link]();
while(radius!=0){
// Send the radius to the server
[Link](radius);
[Link]();
// Get area from the server
area = [Link]();
16
// Display the text
[Link]("Radius is " + radius + "\n");
[Link]("Area received from the server is "+ area +
'\n');
// Get the radius
[Link]("Enter a radius [0 to quit]: ");
radius = [Link]();
}
}
catch (IOException ex) {
[Link]();
}
finally{
try{
[Link]("\n* Closing connection… *");
[Link]();
}catch(IOException ie){
[Link]("Unable to disconnect!");
[Link](1);
}
} 17
}
You start the server program first and then start the client program.
In the client program, enter a radius 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 [Link]. You should import this package
when writing Java network programs.
Note
When you create a server socket, you have to specify a port (e.g., 8000) for the socket.
When a client connects to the server , a socket is created on the client.
This socket has its own local port. This port number (e.g., 2047) is automatically
chosen by the JVM, as shown in the following figure
18
To see the local port on the client, use the following statement
[Link]("local port: " + [Link]());
Reading from a socket blocks until data are available.
If the host is unreachable, your application waits for a long time and you are at the
mercy of the underlying operating system to eventually time out.
You can decide what timeout value is reasonable for your particular application.
Then, call the setSoTimeout method to set a timeout value (in milliseconds).
Socket s = new Socket(. . .);
[Link](10000); // time out after 10 seconds
If the timeout value has been set for a socket, all subsequent read and write operations
throw a SocketTimeoutException when the timeout has been reached before the
operation has completed its work.
You can catch that exception and react to the timeout.
19
try
{
InputStream in = [Link](); // read from in
. . .
}
catch (InterruptedIOException exception)
{
react to timeout
}
There is one additional timeout issue that you need to address. The constructor
Socket(String host, int port)
can block indefinitely until an initial connection to the host is established.
You can overcome this problem by first constructing an unconnected socket and then
connecting it with a timeout:
Socket s = new Socket();
[Link](new InetSocketAddress(host, port), timeout);
20
Sending and Receiving Objects
A program can send and receive objects from another program.
You can send and receive objects using ObjectOutputStream and
ObjectInputStream on socket streams.
To enable passing, the objects must be serializable.
In the below example, The client uses the writeObject method in the
ObjectOutputStream class to send a student to the server, and the server
receives the student using the readObject method in the ObjectInputStream
class.
Example
public class StudentAddress implements [Link]{
private String name;
private String street;
private String city;
private String state;
private String zip;
21
public StudentAddress(String name, String street, String
city, String state, String zip) {
[Link] = name;
[Link] = street;
[Link] = city;
[Link] = state;
[Link] = zip;
}
public String getName() {
return name;
}
public String getStreet() {
return street;
}
public String getCity() {
return city;
}
public String getState() {
return state;
}
public String getZip() {
return zip;
}
} 22
import [Link];
import [Link];
import [Link];
import [Link].*;
import [Link].*;
import [Link];
import [Link];
import [Link];
/**
*
* @author mahhf
*/
public class StudentClientFX extends Application {
private TextField tfName = new TextField();
private TextField tfStreet = new TextField();
private TextField tfCity = new TextField();
private TextField tfState = new TextField();
private TextField tfZip = new TextField();
private String host = "localhost"; 23
private String host = "localhost";
@Override
public void start(Stage primaryStage) {
GridPane grid = new GridPane();
[Link](new Insets(15));
[Link](10);
[Link](10);
[Link](new Label("Name:"), 0, 0);
[Link](tfName, 1, 0);
[Link](new Label("Street:"), 0, 1);
[Link](tfStreet, 1, 1);
[Link](new Label("City:"), 0, 2);
[Link](tfCity, 1, 2);
[Link](new Label("State:"), 0, 3);
[Link](tfState, 1, 3);
[Link](new Label("Zip:"), 0, 4);
[Link](tfZip, 1, 4); 24
Button btnRegister = new Button("Register to Server");
[Link](e -> sendStudent());
VBox root = new VBox(15, grid, btnRegister);
[Link](new Insets(20));
Scene scene = new Scene(root, 400, 300);
[Link]("Student Client (JavaFX)");
[Link](scene);
[Link]();
}
private void sendStudent() {
try (Socket socket = new Socket(host, 8000);
ObjectOutputStream toServer =
new
ObjectOutputStream([Link]())) {
StudentAddress student = new StudentAddress(
[Link]().trim(),
[Link]().trim(),
[Link]().trim(),
[Link]().trim(),
[Link]().trim()); 25
[Link](student);
Alert alert = new Alert([Link],
"Student sent successfully!");
[Link]();
} catch (Exception ex) {
[Link]();
Alert alert = new Alert([Link],
"Error: " + [Link]());
[Link]();
}
}
public static void main(String[] args) {
launch(args);
}
}
26
//The Server
import [Link].*;
import [Link];
import [Link];
/**
*
* @author mahhf
*/
public class StudentServer {
public static void main(String[] args) {
new StudentServer().startServer();
}
public void startServer() {
[Link]("Server started on port
8000...");
try (ServerSocket serverSocket = new
ServerSocket(8000); 27
ObjectOutputStream outputToFile =new ObjectOutputStream(
new FileOutputStream("[Link]", true))) {
while (true) {
try (Socket socket =[Link]();
ObjectInputStream inputFromClient =
new ObjectInputStream([Link]())) {
Object object = [Link]();
[Link](object);
[Link]();
[Link]("New student stored.");
} catch (ClassNotFoundException e) {
[Link]();
}
}
} catch (IOException e) {
[Link]();
}}} 28
Exercise
Write a client that receives the students objects from a server. The server
should read the students objects from the file and sends it to the client up on
request from the client.
29
The InetAddress Class
The server program can use the InetAddress class to obtain the information about
the IP address and host name for the client.
You can use the following statement in the server program to get an instance of
InetAddress on a socket that connects to the client.
InetAddress inetAddress = [Link]();
Next, you can display the client’s host name and IP address, as follows:
[Link]("Client's host name is " +
[Link]());
[Link]("Client's IP Address is " +
[Link]());
You can also create an instance of InetAddress from a host name or IP address
using the static getByName method.
For example, the following statement creates an InetAddress for the host
[Link]
InetAddress address = [Link](“[Link]"); 30
You can access the bytes with the getAddress method.
byte[] addressBytes = [Link]();
Some host names with a lot of traffic correspond to multiple Internet addresses, to
facilitate load balancing.
You can get all hosts with the getAllByName method.
InetAddress[] addresses = [Link](host);
Example
public class InetAddressTest
{
public static void main(String[] args) throws IOException
{
if ([Link] > 0)
{
String host = args[0];
InetAddress[] addresses = [Link](host);
for (InetAddress a : addresses)
[Link](a);
}
31
else
{
InetAddress localHostAddress = [Link]();
[Link](localHostAddress);
}
}
}
Serving Multiple Clients
Typically, a server runs continuously on a server computer, and clients from all over the
Internet can connect to it.
You can use threads to handle the server’s multiple clients simultaneously
For this to happen, the main loop of the server should look like this:
while (true)
{
Socket incoming = [Link]();
Runnable r = new ThreadedHandler(incoming);
Thread t = new Thread(r);
[Link](); 32
}
Or
while (true) {
Socket socket = [Link](); // Connect to a client
Thread thread = new ThreadClass(socket);
[Link]();
}
The server socket can have many connections.
Each iteration of the while loop creates a new connection.
Whenever a connection is established, a new thread is created to handle communication
between the server and the new client, and this allows multiple connections to run at the
same time; As shown below
33
UDP Sockets
When using UDP sockets the connection between the client and the server is not
maintained throughout the communication session.
Each datagram packet is sent as an isolated transmission when necessary.
There are no guarantees that the packets arrive in order at the destination or that the
packets arrive at the destination at all.
Let us see as an example a server that echoes messages received from clients
UDP Sockets—Server Side
Java UDP server communication steps include the following:
• Step 1—Create a datagram socket object.
DatagramSocket dgramSocket = new DatagramSocket(portno);
/*1024 > portno <= 65535*/
• Step 2—Create a buffer to store the incoming datagrams:
byte[] buffer = new byte[256]; //-128 <= byte value <= 127
• Step 3—Create a datagram packet object for incoming datagrams:
DatagramPacket inPkt = new DatagramPacket(buffer, [Link]);
• Step 4—Accept an incoming datagram:
34
[Link](inPkt);
• Step 5—Get sender’s address and port number from the datagram:
InetAddress cliAddress = [Link]();
int cliPort = [Link]();
• Step 6—Retrieve the data from the buffer:
String msgIn = new String([Link](), 0, [Link]());
• Step 7—Create the response datagram:
msgOut = ("Message " + numMessages + ":" + messageIn);
DatagramPacket outPkt = new
DatagramPacket([Link](),[Link](), cliAddress,
cliPort);
• Step 8—Send the response datagram:
[Link](outPkt);
• Step 9—Repeat communication if necessary:
while(condition);
• Step 10—Close the datagram socket:
35
[Link]();
Java UDP socket communication may throw exceptions that need to be caught and
treated.
The following example shows how to catch exceptions thrown by the UDP sockets.
try{
/*attempt to create the socket*/
dgramSocket = new DatagramSocket(PORT);
}
catch (SocketException e) {
/*this exception may be triggered when*/
/*the port is already in use.*/
[Link]("Unable to attach to port!");
[Link](1);
}
UDP Sockets—Client Side
Java UDP client communication steps include:
36
• Step 1—Create a datagram socket object:
DatagramSocket dgramSocket = new DatagramSocket();
/*a default port no will be selected*/
• Step 2—Create the outgoing datagram:
BufferedReader userEntry = new BufferedReader(new
InputStreamReader([Link]));
[Link]("Enter message: ");
String msg = [Link]();
DatagramPacket outPkt = new DatagramPacket([Link](),
[Link](), host, portno);
• Step 3—Send the response datagram:
[Link](outPkt);
• Step 4: Create a buffer to store the incoming datagrams:
byte[] buffer = new byte[256];
• Step 5—Create a datagram packet object for incoming datagrams:
DatagramPacket inPkt = new DatagramPacket(buffer, [Link]);
37
• Step 6—Accept an incoming datagram:
[Link](inPkt);
• Step 7—Retrieve the data from the buffer:
String msgIn = new String([Link](), 0, [Link]());
• Step 8—Close the datagram socket:
[Link]();
38
Example
UDP Server
import [Link];
import [Link];
import [Link];
public class CircleAreaServer {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(9000);
[Link]("UDP Circle Area Server started on
port 9000...");
byte[] receiveBuffer = new byte[1024];
while (true) {
// Receive request from client
DatagramPacket requestPacket = new DatagramPacket(receiveBuffer,
[Link]);
[Link](requestPacket);
String radiusStr = new String( [Link](), 0,
[Link]());
39
double radius = [Link](radiusStr);
// Calculate area
double area = [Link] * radius * radius;
[Link]("Received radius: " + radius);
[Link]("Calculated area: " + area);
// Send response back to client
String areaStr = [Link](area);
byte[] sendBuffer = [Link]();
InetAddress clientAddress = [Link]();
int clientPort = [Link]();
DatagramPacket responsePacket = new DatagramPacket(sendBuffer,
[Link], clientAddress, clientPort);
[Link](responsePacket);
}
}
40
}
//UDP Client
import [Link];
import [Link];
import [Link];
import [Link];
public class CircleAreaClient {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket();
InetAddress serverAddress = [Link]("localhost");
Scanner input = new Scanner([Link]);
[Link]("Enter radius: ");
double radius = [Link]();
41
// Send radius to server
String radiusStr = [Link](radius);
byte[] sendBuffer = [Link]();
DatagramPacket requestPacket = new DatagramPacket(sendBuffer,
[Link],serverAddress, 9000);
[Link](requestPacket);
// Receive area from server
byte[] receiveBuffer = new byte[1024];
DatagramPacket responsePacket = new DatagramPacket(receiveBuffer,
[Link]);
[Link](responsePacket);
String areaStr = new String( [Link](), 0,
[Link]());
42
[Link]("Area received from server: " + areaStr);
[Link]();
}
}
43