Networking
After this lesson you'll be able to open raw TCP/UDP sockets, talk to REST APIs with the modern HttpClient (sync and async, GET and POST), and handle the timeouts and errors that real networks throw at you.
Learn Networking in our free Java course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Java course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
You should know IO & NIO (sockets read and write streams), CompletableFuture (used for async HTTP), and JSON processing (for parsing API responses). A little background on what HTTP is — requests, responses, status codes — also helps.
Networking just means two programs sending bytes to each other across a connection. Java gives you tools at different levels — pick the lowest one that does the job, and the highest one that's still convenient.
💡 Analogy: Think of networking like a phone system . A ServerSocket is a receptionist sitting by a phone (a port ), waiting for calls. A Socket is the live phone line once a call connects — both sides can talk. DatagramSocket (UDP) is more like dropping a postcard in the mailbox: you send it and hope it arrives, with no call and no confirmation. And HttpClient is a smart assistant who already speaks HTTP — you just say "GET me this page" and it dials, talks, and hands you the answer.
A port is just a numbered door on a machine (0–65535). A server "listens" on a port; a client connects to host:port . localhost (address 127.0.0.1 ) means "this same machine".
TCP (Transmission Control Protocol) gives you a reliable, ordered pipe of bytes: everything you send arrives, in order, or you get an error. The server creates a ServerSocket and calls accept() , which blocks until a client connects. The client creates a Socket pointed at host:port . After that, both sides read and write through ordinary streams — exactly the BufferedReader / PrintWriter from the IO lesson.
The worked example below runs a tiny "echo" server (it replies with whatever you send) and a client, in one program. Notice try-with-resources on every socket and stream — that's how you avoid leaks. Read the inline comments and the request/response trace in the output panel.
UDP (User Datagram Protocol) has no connection and no delivery guarantee. You wrap your bytes in a DatagramPacket addressed to a host and port, and send it through a DatagramSocket . The packet might arrive, arrive twice, or vanish — UDP won't tell you. In exchange you get very low overhead, which is why live games, voice, and video use it: a dropped frame matters less than a delayed one.
The receiver binds a DatagramSocket to a port and calls receive() (which blocks for one packet). The sender just builds a packet and calls send() — no handshake.
Most of the time you're not inventing a protocol — you're talking to a web API over HTTP. Java 11 introduced java.net.http.HttpClient , a fluent, modern API that replaces the clunky old HttpURLConnection . It speaks HTTP/2, supports async calls, and pools connections for you.
HttpClient.newHttpClient() — create a client (build once, reuse everywhere)
HttpRequest.newBuilder().uri(...).GET().build() — describe the request
client.send(req, BodyHandlers.ofString()) — send it and block for the response
res.statusCode() / res.body() — read the result (check status first!)
A BodyHandler decides what to turn the response into — ofString() for text/JSON, ofFile(path) to stream straight to disk. To POST data, attach a BodyPublisher like BodyPublishers.ofString(json) . The worked example below does a GET with an Accept header and a JSON POST, then prints both status codes and a slice of the response body.
You pass HttpClient a URI , not a URL. The difference trips people up, so here it is in one line each:
client.send(...) blocks the calling thread until the response comes back. If you have ten URLs to fetch, doing them one after another is slow. client.sendAsync(...) returns immediately with a CompletableFuture , so you can launch many requests at once and they run in parallel.
You chain .thenApply(...) to transform each response, then use CompletableFuture.allOf(...) to wait for every request to finish. The worked example fires three requests together and prints each status code.
Fill in the three ___ blanks to build a request, send it, and print the status code. The expected output is in the comments so you can check yourself.
The server is written for you. Fill in the port and the method that reads one line from the socket's input stream.
Now write it yourself. The starter has only a comment outline — no filled-in logic. Follow the steps and match the expected output.
You can now work at every layer of Java networking: reliable TCP with Socket / ServerSocket , fast UDP with DatagramSocket , and clean REST calls with the modern HttpClient — sync and async, GET and POST, with headers and JSON. Just as important, you know to set timeouts, close sockets with try-with-resources, and check status codes before trusting a response.
Next up: Thread Pools — managing concurrent work efficiently with ExecutorService , the engine behind handling many client connections at once.
Practice quiz
Which class does a TCP server use to listen for incoming connections?
- Socket
- DatagramSocket
- ServerSocket
- HttpClient
Answer: ServerSocket. A server creates a ServerSocket and calls accept(), which blocks until a client connects.
What is the key difference between TCP and UDP?
- TCP is a reliable, ordered connection; UDP is connectionless 'fire and forget'
- TCP is connectionless; UDP is reliable
- They are identical
- UDP guarantees delivery; TCP does not
Answer: TCP is a reliable, ordered connection; UDP is connectionless 'fire and forget'. TCP (Socket/ServerSocket) guarantees ordered, reliable delivery. UDP (DatagramSocket) is lower overhead but may drop, duplicate, or reorder packets.
Which API does UDP use to send a packet?
- Socket
- ServerSocket
- HttpRequest
- DatagramSocket with DatagramPacket
Answer: DatagramSocket with DatagramPacket. UDP wraps bytes in a DatagramPacket addressed to host:port and sends it through a DatagramSocket — no handshake.
Which Java 11+ class is the modern way to make HTTP/REST calls?
- HttpURLConnection
- HttpClient
- URLConnection
- Socket
Answer: HttpClient. java.net.http.HttpClient is the fluent, modern replacement that supports HTTP/2, async calls, and connection pooling.
How do you read the HTTP status code from an HttpResponse?
- res.statusCode()
- res.code()
- res.status()
- res.getStatus()
Answer: res.statusCode(). res.statusCode() returns the numeric status (e.g. 200). Always check it before trusting res.body().
What does client.sendAsync(...) return?
- An HttpResponse
- void
- A CompletableFuture
- A Socket
Answer: A CompletableFuture. sendAsync returns immediately with a CompletableFuture, so the calling thread is not blocked and requests can run in parallel.
Which BodyHandler turns the response into text or JSON you can read as a String?
- BodyHandlers.ofFile(path)
- BodyHandlers.ofString()
- BodyHandlers.discarding()
- BodyHandlers.ofByteArray()
Answer: BodyHandlers.ofString(). BodyHandlers.ofString() collects the response body into a String. ofFile streams it straight to disk instead.
What do you pass to HttpRequest.newBuilder().uri(...)?
- A URL object
- A plain String only
- A Socket
- A URI, e.g. URI.create("https://...")
Answer: A URI, e.g. URI.create("https://..."). HttpClient takes a URI (URI.create(...)). A URI just identifies the resource; HttpClient handles the connection.
What is the cleanest way to make sure sockets and streams are closed?
- Call System.gc()
- try-with-resources
- Leave them for the garbage collector
- Call finalize()
Answer: try-with-resources. try-with-resources closes Socket, ServerSocket, and streams automatically — even when an exception is thrown.
How do you stop an HttpClient.send() from hanging forever on a dead server?
- Nothing — it cannot hang
- Use a faster CPU
- Set connectTimeout on the client and timeout on the request
- Call close() repeatedly
Answer: Set connectTimeout on the client and timeout on the request. Set .connectTimeout(...) on the client and .timeout(...) on the request so a stalled peer eventually throws instead of freezing.