Socket Programming
AdvancedJava sockets enable low-level TCP and UDP communication between processes — the foundation of all networked Java applications.
Overview
Java sockets (java.net package) provide raw TCP and UDP communication. ServerSocket listens for incoming connections; Socket represents a connected endpoint. Each connection has an InputStream and OutputStream for data exchange. For high-concurrency servers, threads or NIO channels (SocketChannel, AsynchronousSocketChannel) replace the simple one-thread-per-connection model. Virtual threads (Java 21) make thread-per-connection scalable again.
TCP Server and Client
ServerSocket.accept() blocks until a client connects, returning a Socket. Read from socket.getInputStream() and write to socket.getOutputStream().
The server should handle each client in a separate thread to serve multiple clients concurrently.
// --- Server ---
try (ServerSocket server = new ServerSocket(8080)) {
System.out.println("Listening on port 8080...");
while (true) {
Socket client = server.accept(); // blocks
// Handle each client in a thread
Thread.ofVirtual().start(() -> handleClient(client));
}
}
void handleClient(Socket socket) {
try (socket;
var in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
var out = new PrintWriter(socket.getOutputStream(), true)) {
String line;
while ((line = in.readLine()) != null) {
out.println("Echo: " + line);
}
} catch (IOException e) { /* log */ }
}
// --- Client ---
try (Socket socket = new Socket("localhost", 8080);
var out = new PrintWriter(socket.getOutputStream(), true);
var in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
out.println("Hello, Server!");
System.out.println(in.readLine()); // Echo: Hello, Server!
}UDP with DatagramSocket
UDP is connectionless and does not guarantee delivery or order. DatagramSocket sends and receives DatagramPacket objects. Suitable for real-time applications (games, video) where low latency matters more than reliability.
UDP packets include the destination address in the packet itself, unlike TCP which establishes a connection.
// UDP Server
try (DatagramSocket server = new DatagramSocket(9090)) {
byte[] buf = new byte[256];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
server.receive(packet); // blocks
String msg = new String(packet.getData(), 0, packet.getLength());
System.out.println("Received: " + msg);
// Echo back
DatagramPacket reply = new DatagramPacket(
packet.getData(), packet.getLength(),
packet.getAddress(), packet.getPort());
server.send(reply);
}
// UDP Client
try (DatagramSocket client = new DatagramSocket()) {
byte[] data = "Hello UDP".getBytes();
InetAddress addr = InetAddress.getByName("localhost");
DatagramPacket packet = new DatagramPacket(data, data.length, addr, 9090);
client.send(packet);
}Non-Blocking NIO Sockets
For high-concurrency servers, NIO SocketChannel with Selector enables a single thread to manage thousands of connections. The selector monitors multiple channels and notifies when they are ready to read/write.
This is the I/O multiplexing pattern (similar to select/epoll on Linux). Virtual threads (Project Loom, Java 21) offer an alternative: thread-per-connection with virtual threads is nearly as efficient as NIO selectors.
// NIO selector-based server (single thread, many connections)
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));
serverChannel.configureBlocking(false);
Selector selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select(); // blocks until at least one event
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iter = keys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
iter.remove();
if (key.isAcceptable()) {
SocketChannel client = serverChannel.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// read from (SocketChannel) key.channel()
}
}
}Key Points to Remember
- ServerSocket.accept() blocks until a client connects; handle each client in a thread.
- Virtual threads (Java 21) make thread-per-connection scalable — prefer over NIO selectors for new code.
- UDP uses DatagramSocket/DatagramPacket; TCP uses Socket/ServerSocket.
- NIO SocketChannel + Selector enables a single thread to multiplex many connections.
- Always close sockets with try-with-resources to release OS file descriptors.
Practice Socket Programming in the Playground
Run and modify code directly in your browser - no setup needed.
Interview Questions
Sign in to ask AriaWhat is the difference between TCP and UDP sockets in Java?
How do you handle multiple concurrent clients in a socket server?
What is the C10K problem and how does NIO Selector address it?
How do virtual threads change the design of socket servers in Java 21?
What is the role of SelectionKey in NIO-based servers?
Ask Aria about Socket Programming
Your personal AI tutor — ask anything about this concept