I/O, Serialization & Networking
Sockets & Networking
Socket + streams on the client, ServerSocket.accept + a thread per connection on the server. Set timeouts on everything, and let virtual threads make thread-per-connection scale again.- Client:
new Socket(host, port)→getInputStream()/getOutputStream() - Server loop:
accept()blocks → hand the socket to a worker - Always set timeouts —
connect(addr, ms)andsetSoTimeout(ms); defaults block forever - Thread-per-connection is simple; Virtual Threads make it scale to 100k+ connections
InetAddressresolves names; UDP usesDatagramSocket/DatagramPacket
try (var socket = new Socket()) {
socket.connect(new InetSocketAddress("time.example.com", 8013), 5_000);
socket.setSoTimeout(10_000); // reads may not hang forever
try (var in = new Scanner(socket.getInputStream(), StandardCharsets.UTF_8)) {
while (in.hasNextLine()) System.out.println(in.nextLine());
}
} // SocketTimeoutException on silence — recoverable, unlike an eternal hangtry (var server = new ServerSocket(8189);
var executor = Executors.newVirtualThreadPerTaskExecutor()) {
while (true) {
Socket client = server.accept(); // blocks until a connection
executor.submit(() -> handle(client)); // cheap thread per client
}
}The blocking model reads top-to-bottom and handles one client per thread. Historically it capped at a few thousand platform threads, pushing servers toward NIO selectors and callback labyrinths. Virtual threads (Virtual Threads) restored the simple model: the JVM parks the virtual thread during blocking I/O and the carrier thread moves on — thread-per-connection semantics at event-loop scale.