Networking in Java

1. Java Networking Overview

Java's java.net package provides classes for network communication. The two primary transport protocols are TCP and UDP:

Feature TCP UDP
Connection Connection-oriented (handshake required) Connectionless
Reliability Guaranteed delivery, ordered packets No guarantee; packets may be lost or reordered
Speed Slower (overhead for reliability) Faster (minimal overhead)
Use cases HTTP, FTP, email, database queries DNS, video streaming, online gaming
Java class Socket / ServerSocket DatagramSocket / DatagramPacket

Key classes in java.net:

  • InetAddress — represents an IP address.
  • Socket — TCP client endpoint.
  • ServerSocket — TCP server endpoint; listens for connections.
  • DatagramSocket — UDP socket (client and server).
  • DatagramPacket — UDP data container.
  • URL — represents a Uniform Resource Locator.
  • HttpURLConnection — makes HTTP requests.

2. InetAddress

InetAddress resolves hostnames to IP addresses and vice versa. It supports both IPv4 and IPv6.

import java.net.InetAddress;
import java.net.UnknownHostException;

public class InetAddressDemo {
    public static void main(String[] args) throws UnknownHostException {
        // Resolve a hostname to IP
        InetAddress google = InetAddress.getByName("www.google.com");
        System.out.println("Host name:    " + google.getHostName());
        System.out.println("Host address: " + google.getHostAddress());
        System.out.println("Is reachable: " + google.isReachable(3000)); // 3s timeout - requires try/catch

        // Get all IP addresses for a hostname (load-balanced services)
        InetAddress[] addresses = InetAddress.getAllByName("www.google.com");
        System.out.println("\nAll IPs for www.google.com:");
        for (InetAddress addr : addresses) {
            System.out.println("  " + addr.getHostAddress());
        }

        // Get local machine information
        InetAddress localhost = InetAddress.getLocalHost();
        System.out.println("\nLocal host name: " + localhost.getHostName());
        System.out.println("Local IP:        " + localhost.getHostAddress());

        // Get loopback address
        InetAddress loopback = InetAddress.getLoopbackAddress();
        System.out.println("Loopback: " + loopback.getHostAddress()); // 127.0.0.1

        // Create from raw IP bytes
        byte[] ipBytes = {(byte)192, (byte)168, 1, 1};
        InetAddress custom = InetAddress.getByAddress(ipBytes);
        System.out.println("Custom IP: " + custom.getHostAddress()); // 192.168.1.1
    }
}
Host name: www.google.com
Host address: 142.250.80.4
Local host name: MyPC
Local IP: 192.168.1.5
Loopback: 127.0.0.1
Custom IP: 192.168.1.1

3. Socket Programming — TCP

TCP (Transmission Control Protocol) is connection-oriented. Before data flows, a three-way handshake establishes a reliable, bidirectional connection between client and server. Java models this with two classes:

  • Server side: ServerSocket binds to a port and waits via accept().
  • Client side: Socket connects to the server's host and port.

Once connected, both ends communicate through InputStream and OutputStream obtained from the socket — just like reading and writing a file.

Port numbers: Well-known ports are 0–1023 (HTTP=80, HTTPS=443). Use ports 1024–65535 for your own servers. Both server and client must agree on the same port number.

4. ServerSocket

The server binds to a port, accepts incoming connections in a loop, and typically spawns a new thread per client to handle multiple clients concurrently.

import java.net.*;
import java.io.*;

public class EchoServer {
    private static final int PORT = 9090;

    public static void main(String[] args) throws IOException {
        System.out.println("Server starting on port " + PORT + "...");

        // Bind to port; backlog of 5 queued connections
        try (ServerSocket serverSocket = new ServerSocket(PORT, 5)) {
            System.out.println("Server listening. Waiting for client...");

            while (true) { // keep accepting connections
                Socket clientSocket = serverSocket.accept(); // BLOCKS until a client connects
                System.out.println("Client connected: "
                    + clientSocket.getInetAddress().getHostAddress());

                // Handle each client in a separate thread
                new Thread(() -> handleClient(clientSocket)).start();
            }
        }
    }

    private static void handleClient(Socket socket) {
        try (socket;
             BufferedReader in  = new BufferedReader(
                 new InputStreamReader(socket.getInputStream()));
             PrintWriter   out  = new PrintWriter(
                 socket.getOutputStream(), true)) {  // autoFlush=true

            String line;
            while ((line = in.readLine()) != null) {
                System.out.println("Received: " + line);
                out.println("ECHO: " + line); // echo back to client
                if ("bye".equalsIgnoreCase(line)) break;
            }
        } catch (IOException e) {
            System.err.println("Client error: " + e.getMessage());
        }
        System.out.println("Client disconnected.");
    }
}

5. Socket (Client)

The client creates a Socket with the server's hostname and port. This triggers the TCP handshake. The client then communicates through streams.

import java.net.*;
import java.io.*;

public class EchoClient {
    public static void main(String[] args) throws IOException {
        String host = "localhost";
        int port    = 9090;

        System.out.println("Connecting to " + host + ":" + port);

        try (Socket socket = new Socket(host, port);
             PrintWriter  out = new PrintWriter(
                 socket.getOutputStream(), true);
             BufferedReader in = new BufferedReader(
                 new InputStreamReader(socket.getInputStream()));
             BufferedReader keyboard = new BufferedReader(
                 new InputStreamReader(System.in))) {

            System.out.println("Connected! Type messages (type 'bye' to quit):");
            String userInput;
            while ((userInput = keyboard.readLine()) != null) {
                out.println(userInput);           // send to server
                String response = in.readLine();  // read server response
                System.out.println("Server: " + response);
                if ("bye".equalsIgnoreCase(userInput)) break;
            }
        }
        System.out.println("Connection closed.");
    }
}
Connecting to localhost:9090
Connected! Type messages (type 'bye' to quit):
> Hello Server
Server: ECHO: Hello Server
> bye
Server: ECHO: bye
Connection closed.

6. Complete TCP Client-Server Example

Here is a self-contained example showing both server and client. Run the server first in one terminal, then the client in another.

Server — TimeServer.java

import java.net.*;
import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class TimeServer {
    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(8080)) {
            System.out.println("TimeServer running on port 8080...");
            while (true) {
                try (Socket client = server.accept();
                     PrintWriter out = new PrintWriter(
                         client.getOutputStream(), true)) {
                    String time = LocalDateTime.now()
                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                    out.println("Current server time: " + time);
                    System.out.println("Served time to: "
                        + client.getInetAddress().getHostAddress());
                }
            }
        }
    }
}

Client — TimeClient.java

import java.net.*;
import java.io.*;

public class TimeClient {
    public static void main(String[] args) throws IOException {
        try (Socket socket = new Socket("localhost", 8080);
             BufferedReader in = new BufferedReader(
                 new InputStreamReader(socket.getInputStream()))) {
            System.out.println(in.readLine()); // prints server time
        }
    }
}
-- Terminal 1 (Server) --
TimeServer running on port 8080...
Served time to: 127.0.0.1

-- Terminal 2 (Client) --
Current server time: 2026-07-23 10:30:45

7. UDP with DatagramSocket

UDP is connectionless — you send a packet and the receiver may or may not get it. Each message is a DatagramPacket. There is no stream; each send/receive is independent.

import java.net.*;

// UDP Server
public class UDPServer {
    public static void main(String[] args) throws Exception {
        DatagramSocket serverSocket = new DatagramSocket(9999);
        byte[] receiveBuffer = new byte[1024];

        System.out.println("UDP Server listening on port 9999...");
        while (true) {
            DatagramPacket receivePacket =
                new DatagramPacket(receiveBuffer, receiveBuffer.length);
            serverSocket.receive(receivePacket); // blocks until packet arrives

            String message = new String(receivePacket.getData(), 0,
                                        receivePacket.getLength());
            System.out.println("Received: " + message);

            // Send response back to sender
            InetAddress clientAddr = receivePacket.getAddress();
            int clientPort = receivePacket.getPort();
            String reply = "ACK: " + message;
            byte[] sendBuffer = reply.getBytes();
            DatagramPacket sendPacket =
                new DatagramPacket(sendBuffer, sendBuffer.length,
                                   clientAddr, clientPort);
            serverSocket.send(sendPacket);
        }
    }
}

// UDP Client
public class UDPClient {
    public static void main(String[] args) throws Exception {
        DatagramSocket clientSocket = new DatagramSocket();
        InetAddress serverAddr = InetAddress.getByName("localhost");

        String message = "Hello UDP Server!";
        byte[] sendBuffer = message.getBytes();

        // Send the packet
        DatagramPacket sendPacket =
            new DatagramPacket(sendBuffer, sendBuffer.length, serverAddr, 9999);
        clientSocket.send(sendPacket);
        System.out.println("Sent: " + message);

        // Receive the response
        byte[] receiveBuffer = new byte[1024];
        DatagramPacket receivePacket =
            new DatagramPacket(receiveBuffer, receiveBuffer.length);
        clientSocket.receive(receivePacket);

        String response = new String(receivePacket.getData(), 0,
                                     receivePacket.getLength());
        System.out.println("Response: " + response);

        clientSocket.close();
    }
}
-- UDP Client output --
Sent: Hello UDP Server!
Response: ACK: Hello UDP Server!

8. URL Class

The URL class represents a Uniform Resource Locator and can open a connection to read content from it. This is the simplest way to fetch web content.

import java.net.*;
import java.io.*;

public class URLDemo {
    public static void main(String[] args) throws Exception {
        URL url = new URL("https://jsonplaceholder.typicode.com/posts/1");

        System.out.println("Protocol: " + url.getProtocol()); // https
        System.out.println("Host:     " + url.getHost());     // jsonplaceholder...
        System.out.println("Port:     " + url.getPort());     // -1 (default)
        System.out.println("Path:     " + url.getPath());     // /posts/1

        // Open connection and read content
        System.out.println("\nFetching content...");
        try (BufferedReader reader = new BufferedReader(
                 new InputStreamReader(url.openStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        }
    }
}
Protocol: https
Host: jsonplaceholder.typicode.com
Path: /posts/1

Fetching content...
{
"userId": 1,
"id": 1,
"title": "sunt aut facere..."
}

9. HttpURLConnection

HttpURLConnection provides control over HTTP method, headers, request body, and response codes — needed for REST API calls and form submissions.

GET Request

import java.net.*;
import java.io.*;

public class HttpGetDemo {
    public static void main(String[] args) throws Exception {
        URL url = new URL("https://jsonplaceholder.typicode.com/users/1");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        conn.setRequestMethod("GET");
        conn.setRequestProperty("Accept", "application/json");
        conn.setConnectTimeout(5000); // 5s connect timeout
        conn.setReadTimeout(5000);    // 5s read timeout

        int responseCode = conn.getResponseCode();
        System.out.println("Response Code: " + responseCode); // 200

        if (responseCode == HttpURLConnection.HTTP_OK) {
            try (BufferedReader reader = new BufferedReader(
                     new InputStreamReader(conn.getInputStream()))) {
                StringBuilder response = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    response.append(line).append("\n");
                }
                System.out.println("Response body:\n" + response);
            }
        }
        conn.disconnect();
    }
}

POST Request

import java.net.*;
import java.io.*;

public class HttpPostDemo {
    public static void main(String[] args) throws Exception {
        URL url = new URL("https://jsonplaceholder.typicode.com/posts");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
        conn.setRequestProperty("Accept", "application/json");
        conn.setDoOutput(true); // enable sending a request body

        // Write JSON request body
        String jsonBody = "{\"title\":\"Java Post\",\"body\":\"Hello World\",\"userId\":1}";
        try (OutputStream os = conn.getOutputStream();
             OutputStreamWriter writer = new OutputStreamWriter(os, "UTF-8")) {
            writer.write(jsonBody);
            writer.flush();
        }

        int responseCode = conn.getResponseCode();
        System.out.println("POST Response Code: " + responseCode); // 201

        try (BufferedReader reader = new BufferedReader(
                 new InputStreamReader(conn.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        }
        conn.disconnect();
    }
}
Response Code: 200
POST Response Code: 201
{
"id": 101,
"title": "Java Post",
"body": "Hello World",
"userId": 1
}

Modern alternative: Java 11 introduced java.net.http.HttpClient which is more modern, supports HTTP/2, and has a cleaner API. Prefer it for new projects targeting Java 11+.

10. Common Networking Exceptions

Exception When It Occurs Handling
UnknownHostException Hostname cannot be resolved via DNS (typo, no internet, DNS failure). Validate input; show user-friendly message; check connectivity.
ConnectException Connection refused — server is not running or the port is closed. Check that server is running; verify port number; firewall rules.
SocketTimeoutException Connection or read exceeded the timeout set via setSoTimeout(). Retry with backoff; increase timeout; inform user of slow response.
BindException Server cannot bind to a port (already in use, or no permission for port < 1024). Try a different port; check running processes with netstat.
SocketException General socket error — connection reset, broken pipe, network unreachable. Parent of many network exceptions; log the message; gracefully close socket.
import java.net.*;
import java.io.*;

public class RobustClientDemo {
    public static void fetchData(String host, int port) {
        try {
            Socket socket = new Socket();
            socket.connect(new InetSocketAddress(host, port), 3000); // 3s timeout
            socket.setSoTimeout(5000); // 5s read timeout

            try (socket;
                 BufferedReader in = new BufferedReader(
                     new InputStreamReader(socket.getInputStream()))) {
                System.out.println("Connected: " + in.readLine());
            }
        } catch (UnknownHostException e) {
            System.err.println("Cannot resolve host: " + host);
        } catch (ConnectException e) {
            System.err.println("Connection refused on " + host + ":" + port);
        } catch (SocketTimeoutException e) {
            System.err.println("Timed out connecting to " + host);
        } catch (IOException e) {
            System.err.println("Network error: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        fetchData("localhost", 8080);
        fetchData("nonexistent.invalid", 80);
        fetchData("localhost", 9999); // nothing running
    }
}

Continue learning