Java Network Programming Fundamentals
Network Communication Overview
Network communication requires two essential elements:
- Addressing: IP address and port number identify communicating endpoints
- Protocols: Standardized rules governing data exchange (OSI reference model vs TCP/IP model)
The TCP/IP model became the de facto standard despite the OSI model's theoretical elegance. When developing networked applications, two core challenges emerge: locating specific hosts and applications on the network, and ensuring reliable data transmission between them.
IP Addresses and Port Numbers
Working with InetAddress
An IP address uniquely identifies a machine on the Internet. IPv4 addresses consist of four bytes represented in dotted decimal notation (e.g., 192.168.0.1), while IPv6 uses 128-bit addresses expressed as eight hexadecimal groups. Private addresses in ranges like 192.168.x.x are reserved for local networks.
The InetAddress class represents IP addresses in Java. Domain names resolve to IP addresses through DNS servers, allowing human-readable identifiers like "www.example.com" to map to numeric addresses.
import java.net.InetAddress;
import java.net.UnknownHostException;
public class AddressDemo {
public static void main(String[] args) {
try {
// Query specific IP address
InetAddress remote = InetAddress.getByName("192.168.10.14");
System.out.println("Host: " + remote);
// Query domain name
InetAddress domain = InetAddress.getByName("www.example.com");
System.out.println("Domain: " + domain);
// Local loopback address
InetAddress loopback = InetAddress.getByName("127.0.0.1");
System.out.println("Loopback: " + loopback);
// Get current machine address
InetAddress local = InetAddress.getLocalHost();
System.out.println("Local: " + local);
// Extract hostname and IP string
System.out.println("Name: " + domain.getHostName());
System.out.println("Address: " + domain.getHostAddress());
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
Understanding Port Numbers
A port number identifies a specific application or process running on a host. Ports range from 0 to 65535, with well-known ports (0-1023) reserved for standard services like HTTP (80), FTP (21), and SSH (22). Registered ports (1024-49151) serve applications like Tomcat (8080) and MySQL (3306), while dynamic ports (49152-65535) are available for temporary connections.
The combination of IP address and port number forms a socket, the fundamental endpoint for network communication.
Network Protocols
Layered Protocol Design
Network protocols follow a layered architecture where each layer handles specific responsibilities. Higher layers invoke services from lower layers without concern for implementation details. This separation allows independent evolution of each layer.
TCP vs UDP Comparison
TCP (Transmission Control Protocol) provides connection-oriented, reliable communication:
- Establishes connections using a three-way handshake mechanism
- Guarantees ordered delivery and error correction
- Suitable for applications requiring data integrity
- Higher overhead due to connection management and flow control
UDP (User Datagram Protocol) offers connectionless, lightweight communication:
- No connection establishment required
- Maximum packet size limited to 64KB
- Fire-and-forget delivery without acknowledgment
- Supports broadcasting to multiple recipients
- Ideal for real-time applications where speed matters more than reliability
TCP Socket Programming
Basic Client-Server Communication
TCP communication requires a server listening on a designated port and clients initiating connections. The following example demonstrates bidirectional message exchange.
import org.junit.Test;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpCommunication {
@Test
public void clientSide() {
Socket connection = null;
OutputStream output = null;
try {
connection = new Socket("192.168.14.100", 8899);
output = connection.getOutputStream();
output.write("Greetings from client".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
closeQuietly(output);
closeQuietly(connection);
}
}
@Test
public void serverSide() {
ServerSocket server = null;
Socket clientSocket = null;
InputStream input = null;
ByteArrayOutputStream buffer = null;
try {
server = new ServerSocket(8899);
clientSocket = server.accept();
input = clientSocket.getInputStream();
buffer = new ByteArrayOutputStream();
byte[] data = new byte[5];
int bytesRead;
while ((bytesRead = input.read(data)) != -1) {
buffer.write(data, 0, bytesRead);
}
System.out.println("Received: " + buffer.toString());
System.out.println("Client address: " +
clientSocket.getInetAddress().getHostAddress());
} catch (IOException e) {
e.printStackTrace();
} finally {
closeQuietly(buffer);
closeQuietly(input);
closeQuietly(clientSocket);
closeQuietly(server);
}
}
private void closeQuietly(Closeable resource) {
if (resource != null) {
try {
resource.close();
} catch (IOException ignored) {}
}
}
}
File Transfer Implementation
Transferring files over TCP requires reading binary data and writing it to the output stream. The client reads from a local file and sends it; the server receives and writes to disk.
import org.junit.Test;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class FileTransfer {
@Test
public void uploadFile() throws IOException {
Socket socket = new Socket("127.0.0.1", 9090);
InputStream fileInput = new FileInputStream("image.jpg");
OutputStream networkOutput = socket.getOutputStream();
byte[] chunk = new byte[1024];
int transferred;
while ((transferred = fileInput.read(chunk)) != -1) {
networkOutput.write(chunk, 0, transferred);
}
fileInput.close();
networkOutput.close();
socket.close();
}
@Test
public void downloadFile() throws IOException {
ServerSocket server = new ServerSocket(9090);
Socket client = server.accept();
InputStream fromClient = client.getInputStream();
OutputStream fileOutput = new FileOutputStream("received.jpg");
byte[] chunk = new byte[1024];
int transferred;
while ((transferred = fromClient.read(chunk)) != -1) {
fileOutput.write(chunk, 0, transferred);
}
fileOutput.close();
fromClient.close();
client.close();
server.close();
}
}
File Transfer with Server Response
Enhancing the file transfer with server feedback involves shutting down the output stream to signal completion, then reading the resposne.
import org.junit.Test;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class FileTransferWithResponse {
@Test
public void clientSends() throws IOException {
Socket socket = new Socket("127.0.0.1", 9090);
OutputStream out = socket.getOutputStream();
InputStream fileIn = new FileInputStream("photo.jpg");
byte[] buffer = new byte[1024];
int count;
while ((count = fileIn.read(buffer)) != -1) {
out.write(buffer, 0, count);
}
fileIn.close();
// Signal end of data
socket.shutdownOutput();
// Read server response
InputStream responseIn = socket.getInputStream();
ByteArrayOutputStream responseBuffer = new ByteArrayOutputStream();
byte[] responseData = new byte[20];
int responseCount;
while ((responseCount = responseIn.read(responseData)) != -1) {
responseBuffer.write(responseData, 0, responseCount);
}
System.out.println("Server says: " + responseBuffer.toString());
out.close();
responseBuffer.close();
socket.close();
}
@Test
public void serverReceives() throws IOException {
ServerSocket server = new ServerSocket(9090);
Socket client = server.accept();
InputStream in = client.getInputStream();
OutputStream fileOut = new FileOutputStream("saved_photo.jpg");
byte[] buffer = new byte[1024];
int count;
while ((count = in.read(buffer)) != -1) {
fileOut.write(buffer, 0, count);
}
fileOut.close();
// Send confirmation back to client
OutputStream responseOut = client.getOutputStream();
responseOut.write("File received successfully".getBytes());
in.close();
responseOut.close();
client.close();
server.close();
}
}
UDP Socket Programming
UDP provides a connectionless communication model using DatagramSocket and DatagramPacket. Each packet carries complete destination information, eliminating the need for connection establishment.
import org.junit.Test;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UdpCommunication {
@Test
public void sendMessage() throws IOException {
DatagramSocket socket = new DatagramSocket();
String message = "UDP packet content";
byte[] data = message.getBytes();
InetAddress target = InetAddress.getLocalHost();
DatagramPacket packet = new DatagramPacket(
data, data.length, target, 9090
);
socket.send(packet);
socket.close();
}
@Test
public void receiveMessage() throws IOException {
DatagramSocket socket = new DatagramSocket(9090);
byte[] buffer = new byte[100];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet);
String received = new String(
packet.getData(), 0, packet.getLength()
);
System.out.println("Received: " + received);
socket.close();
}
}
URL Programming
URL Structure and Parsing
A URL encodes multiple components: protocol, host, port, path, and query parameters. The URL class provides accessor methods to extract each part.
import java.net.MalformedURLException;
import java.net.URL;
public class UrlDemo {
public static void main(String[] args) {
try {
URL resource = new URL(
"http://127.0.0.1:8080/images/photo.jpg?user=admin"
);
System.out.println("Protocol: " + resource.getProtocol());
System.out.println("Host: " + resource.getHost());
System.out.println("Port: " + resource.getPort());
System.out.println("Path: " + resource.getPath());
System.out.println("File: " + resource.getFile());
System.out.println("Query: " + resource.getQuery());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
Downloading via HTTP
Establishing an HTTP connection and reading response data requires proper connection management and stream handling.
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpDownload {
public static void main(String[] args) {
HttpURLConnection connection = null;
InputStream response = null;
FileOutputStream fileWriter = null;
try {
URL endpoint = new URL(
"http://127.0.0.1:8080/work/image.jpg"
);
connection = (HttpURLConnection) endpoint.openConnection();
connection.connect();
response = connection.getInputStream();
fileWriter = new FileOutputStream("downloaded.jpg");
byte[] chunk = new byte[1024];
int bytesRead;
while ((bytesRead = response.read(chunk)) != -1) {
fileWriter.write(chunk, 0, bytesRead);
}
System.out.println("Download completed");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (response != null) {
try { response.close(); } catch (IOException ignored) {}
}
if (fileWriter != null) {
try { fileWriter.close(); } catch (IOException ignored) {}
}
if (connection != null) {
connection.disconnect();
}
}
}
}
URI, URL, and URN Distinctions
URI (Uniform Resource Identifier) serves as the umbrella term for resource identification. URL (Uniform Resource Locator) specifies both identity and location information, enabling resource retrieval. URN (Uniform Resource Name) provides persistent, location-independent identifiers through schemes like mailto.
In Java, a URI instance may represent relative references without location data, while a URL must contain sufficient information to locate the resource explicitly.