Why is network programming in Java a superpower?
Imagine: you write code, and suddenly your program starts communicating with another program on the other side of the world. It sends requests, receives responses, synchronizes data — all in milliseconds. This is not magic, this is network programming in Java. If you want to create not just local utilities, but real distributed systems, chats, online games or REST services — you can't do without network programming.
Java provides a powerful toolkit for this: from classic Socket and ServerSocket to high-performance Java NIO (Non-blocking I/O) and modern WebSockets. In this article, we will cover all three approaches, write live code, and understand how to choose the right tool for your task. Let's go!
1. Classic Sockets: TCP Chat "On the Fly"
Let's start with the fundamentals. Sockets in Java are the entry point into the world of TCP/IP. The server creates a ServerSocket, listens on a port, and accepts connections. The client creates a Socket and connects to the server. It's as simple as two plus two.
Writing a Simple Echo Server
The server receives a message from the client and sends it back (echo). The code is minimal but illustrates the whole essence:
import java.io.*;import java.net.*;
public class EchoServer { public static void main(String[] args) { try (ServerSocket serverSocket = new ServerSocket(12345)) { System.out.println("Server started on port 12345..."); Socket clientSocket = serverSocket.accept(); // blocks until connection System.out.println("Client connected: " + clientSocket.getInetAddress());
BufferedReader in = new BufferedReader( new InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter( clientSocket.getOutputStream(), true);
String inputLine; while ((inputLine = in.readLine()) != null) { System.out.println("Received: " + inputLine); out.println("Echo: " + inputLine); if (inputLine.equalsIgnoreCase("exit")) break; } } catch (IOException e) { e.printStackTrace(); } }}And here is the client that sends messages:
import java.io.*;import java.net.*;
public class EchoClient { public static void main(String[] args) throws IOException { Socket socket = new Socket("localhost", 12345); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); BufferedReader stdIn = new BufferedReader( new InputStreamReader(System.in));
String userInput; System.out.println("Enter message (exit to quit):"); while ((userInput = stdIn.readLine()) != null) { out.println(userInput); System.out.println("Server response: " + in.readLine()); if (userInput.equalsIgnoreCase("exit")) break; } socket.close(); }}What is important here? The accept() and readLine() methods block the thread. This means that while one client is communicating, others wait. The solution is multithreading.
Multithreaded Server: Handling Many Clients
For each new connection, we create a separate thread. We use the ExecutorService thread pool to avoid creating thousands of threads unnecessarily:
import java.io.*;import java.net.*;import java.util.concurrent.*;
public class MultiThreadedServer { private static final int PORT = 12345; private static final ExecutorService threadPool = Executors.newFixe