Java Networking
Master socket programming and HTTP servers in Java. Complete each lesson, pass the exercises, and watch your progress climb to 100%.
| # | Lesson | Exercise type | Marks |
|---|---|---|---|
| 1 | Networking Basics | MCQ | 10 |
| 2 | Streams & Wrappers | Fill Blanks | 10 |
| 3 | ServerSocket | MCQ | 10 |
| 4 | Multi-threading | Fill Blanks | 10 |
| 5 | Resource Cleanup | Code Order | 10 |
| 6 | HTTP Fundamentals | MCQ | 10 |
| 7 | HttpServer Setup | Fill Blanks | 10 |
| 8 | HttpExchange | MCQ | 10 |
| 9 | Headers & Body | Fill Blanks | 10 |
| 10 | Final Challenge | Debug & MCQ | 10 |
Read each lesson, then complete the exercise at the bottom. Every completed exercise adds 10% to your overall progress. You need to score at least 1 correct answer to unlock the lesson as done.
Networking Basics
Understand IP addresses, ports, TCP, and why sockets exist — the mental models you need before writing a single line of code.
Networking is just two programs talking to each other. Think of it exactly like a phone call:
• The server is like a business with a listed phone number — it waits for calls.
• The client dials in — it initiates the connection.
• Once connected, both sides can talk and listen simultaneously.
| Port | Common use |
|---|---|
| 80 | HTTP (websites) |
| 443 | HTTPS (secure websites) |
| 8000 | Development HTTP servers |
| 6666 | Our custom socket server |
| Feature | TCP (Raw Socket) | HTTP |
|---|---|---|
| Level | Low-level transport | Built on top of TCP |
| Format | Raw bytes / text | Structured (headers + body) |
| Java class | ServerSocket | HttpServer |
| Use case | Chat, game servers | Web APIs, browsers |
HTTP doesn't replace TCP — it's built on top of it. Every HTTP request is a TCP connection under the hood. Java's HttpServer abstracts all of that for you.
Q1. What does a port number identify?
Q2. Which Java class is used to build a raw TCP socket server?
ServerSocket is the TCP listener. HttpServer is the higher-level HTTP abstraction.ServerSocket is the raw TCP listener in Java's java.net package.Q3. HTTP is built on top of which protocol?
Streams & Wrappers
Data flows through sockets as raw bytes. You'll learn the three-layer wrapping pattern that turns those bytes into readable lines of text.
// Step 1: raw bytes from socket
InputStream rawIn = clientSocket.getInputStream();
// Step 2: convert bytes to characters
InputStreamReader charReader = new InputStreamReader(rawIn);
// Step 3: efficient line-by-line reading
BufferedReader in = new BufferedReader(charReader);
// Or all in one line (most common):
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream())
);
String line = in.readLine(); // blocks until a line arrives
// true = auto-flush: data sent IMMEDIATELY after println()
PrintWriter out = new PrintWriter(
clientSocket.getOutputStream(), true
);
out.println("Hello, client!"); // sent right away
Always pass true as the second argument to PrintWriter. Without it, your messages sit in a buffer and the client never receives them until you manually call out.flush() or close the stream.
Think of the wrappers like Russian dolls — each one adds a capability. InputStream = raw bytes. InputStreamReader = speaks English. BufferedReader = reads full sentences.
Fill in each blank with the correct class or method name. Case-sensitive.
Q1. Complete the three-layer reading chain:
Q2. Create a PrintWriter with auto-flush enabled:
Q3. Which method reads a full line from a BufferedReader?
ServerSocket — The Listener
ServerSocket is your server's front door. Learn how to create it, bind it to a port, and accept incoming client connections.
// Bind to port 6666, IOException must be handled
ServerSocket serverSocket = new ServerSocket(6666);
// Block until a client connects — returns a live Socket
Socket clientSocket = serverSocket.accept();
// Loop to accept MANY clients (one at a time, sequentially)
while (true) {
Socket client = serverSocket.accept(); // waits here
// handle client...
}
new ServerSocket(port) throws IOException. Always wrap it in a try-catch or declare throws IOException on the method. The port must be between 1 and 65535, and not already in use.
The backlog (second optional argument) is how many pending connections can queue up before the OS starts rejecting them. new ServerSocket(6666) uses the OS default. For the exam, always use 0 with HttpServer's factory method.
Q1. What does serverSocket.accept() return?
accept() blocks until a client connects, then returns a Socket object representing that client's connection.accept() returns a Socket — one live connection to one specific client.Q2. What exception must you handle when creating a ServerSocket?
IOException is thrown if the port is already in use or another OS-level error occurs.ServerSocket throws IOException — a checked exception you must handle.Q3. What does accept() do while waiting for a client?
accept() is a blocking call — execution pauses right there until a client connects.accept() blocks — the thread is paused at that line until a client shows up.Multi-threading
Handle multiple clients simultaneously using threads and the Runnable pattern — the heart of a real server.
while (true) {
Socket client = serverSocket.accept(); // wait
ClientHandler handler = new ClientHandler(client); // create
Thread thread = new Thread(handler); // wrap
thread.start(); // launch (non-blocking!)
// loop IMMEDIATELY back to accept() for next client
}
private static class ClientHandler implements Runnable {
private final Socket clientSocket;
public ClientHandler(Socket socket) {
this.clientSocket = socket; // store the connection
}
@Override
public void run() {
// This runs in a separate thread
// Set up streams, echo loop, cleanup...
}
}
static means the inner class doesn't hold a reference to the outer class. This prevents accidental memory leaks — the handler only needs the Socket, nothing else from the outer SocketServerExam class.
String inputLine;
while ((inputLine = in.readLine()) != null) {
// readLine() returns null when client disconnects
System.out.println("Received: " + inputLine);
out.println("Echo: " + inputLine);
}
Q1. Complete the multi-threaded accept loop:
Q2. What interface does ClientHandler implement?
Q3. What value does readLine() return when the client disconnects?
Resource Cleanup
Network resources must always be closed — even when exceptions occur. Master the finally block and try-with-resources patterns.
// Declare BEFORE try so finally can see them
BufferedReader in = null;
PrintWriter out = null;
try {
in = new BufferedReader(...);
out = new PrintWriter(..., true);
// communicate...
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
} finally {
// ALWAYS runs — even after an exception
try {
if (clientSocket != null) clientSocket.close();
if (in != null) in.close();
if (out != null) out.close();
} catch (IOException e) { e.printStackTrace(); }
}
// Resources in () are auto-closed when block exits
try (Socket client = serverSocket.accept();
BufferedReader in = new BufferedReader(
new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(
client.getOutputStream(), true)) {
String line;
while ((line = in.readLine()) != null) {
out.println("Echo: " + line);
}
} // client, in, out all closed automatically here
Declare BufferedReader in = null and PrintWriter out = null before the try block. If you declare them inside the try, the finally block can't see them — Java scoping rule.
Click the code chips in the correct order to build the finally cleanup block. Click a placed chip to remove it.
} finally { try { ___ ___ ___ } catch(IOException e) { e.printStackTrace(); } }
HTTP Fundamentals
Learn the structure of HTTP requests and responses, common methods, and status codes — the vocabulary of the web.
| Method | Purpose | Has body? |
|---|---|---|
| GET | Retrieve data (load a page) | No |
| POST | Send data to server | Yes |
| PUT | Update existing data | Yes |
| DELETE | Remove data | No |
| Code | Meaning | When |
|---|---|---|
| 200 | OK | Request succeeded |
| 201 | Created | Resource was created |
| 400 | Bad Request | Client sent bad data |
| 404 | Not Found | Path doesn't exist |
| 405 | Method Not Allowed | Wrong verb (e.g., GET on POST route) |
| 500 | Internal Server Error | Something crashed on the server |
2xx = Success 3xx = Redirect 4xx = Client's fault 5xx = Server's fault
Q1. Your server's /data route only accepts POST. A client sends a GET request. What status code should you return?
Q2. Which HTTP method is used for sending a new data payload to the server (like submitting a form)?
Q3. What separates the headers from the body in an HTTP request?
HttpServer Setup
Create and configure Java's built-in HTTP server — factory method, routing with contexts, and executors.
// Factory method — NOT "new HttpServer(...)"
HttpServer server = HttpServer.create(
new InetSocketAddress(8000), // bind to port 8000
0 // backlog = 0 (OS default)
);
server.createContext("/", new RootHandler());
server.createContext("/data", new DataHandler());
server.setExecutor(null); // default single-threaded
server.start(); // begin accepting connections
| setExecutor(…) | Behaviour | Use case |
|---|---|---|
null | Single-threaded, one request at a time | Exams, demos |
Executors.newFixedThreadPool(10) | Max 10 concurrent requests | Production |
Executors.newCachedThreadPool() | Dynamic — scales up/down | Variable load |
HttpServer.create() is a factory method — you call it on the class itself, not with new. This is common in Java when the actual implementation returned may vary. You always get an HttpServer back regardless.
Q1. Create an HttpServer on port 8000:
Q2. Register routes and start:
HttpExchange
The HttpExchange object is your window into every request — and your tool to write every response. Master its API.
String response = "<html><body><h1>Hello</h1></body></html>";
// Step 1: Set response headers (optional, do this FIRST)
exchange.getResponseHeaders().set("Content-Type", "text/html");
// Step 2: Send status code + byte count
exchange.sendResponseHeaders(200, response.getBytes().length);
// Step 3: Write body and close
try (OutputStream os = exchange.getResponseBody()) {
os.write(response.getBytes());
} // auto-closed here
1. Always call sendResponseHeaders() before writing the body.
2. Always close() the OutputStream — the client waits forever without it.
3. Use -1 as content length when there's no body (e.g., 405 responses).
Q1. What content length should you pass to sendResponseHeaders() when there is no response body?
-1 signals "no body follows". Using 0 would tell the client a body of exactly zero bytes is coming — causing it to hang.-1 for no-body responses. 0 has a different meaning and causes clients to hang.Q2. Which method gives you an OutputStream to write the HTTP response body?
getResponseBody() returns the OutputStream you write your response into.getResponseBody() gives the OutputStream for writing the response. getRequestBody() is for reading.Q3. In what order must these three steps happen?
Headers & Request Body
Read what the client sends — headers for metadata, the body for POST data — and respond with the right Content-Type.
// Get the Headers map
Headers requestHeaders = exchange.getRequestHeaders();
// Read one header (case-insensitive key)
String userAgent = requestHeaders.getFirst("User-Agent");
System.out.println("User-Agent: " + userAgent);
// Headers is like Map<String, List<String>>
// getFirst() returns the first value for that key
// Get the input stream
InputStream inputStream = exchange.getRequestBody();
// Read ALL bytes at once (Java 9+)
byte[] requestBody = inputStream.readAllBytes();
// Convert to String if text
String bodyText = new String(requestBody);
String json = "{ \"status\": \"success\" }";
// IMPORTANT: set Content-Type BEFORE sendResponseHeaders
exchange.getResponseHeaders().set(
"Content-Type",
"application/json"
);
exchange.sendResponseHeaders(200, json.getBytes().length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(json.getBytes());
}
Even if you don't use the POST body, call getRequestBody().readAllBytes(). Some HTTP clients wait for the server to consume the request before reading the response — not reading it can cause the client to hang.
Q1. Read the User-Agent request header:
Q2. Read all bytes from the request body:
Q3. Set the response Content-Type to JSON:
Final Challenge
Prove you've mastered everything — spot the bugs, fill the blanks, and answer the comprehensive MCQ to complete the course.
The code below has 3 bugs. Find them before doing the MCQ!
// Bug Hunt Exercise
// Bug 1 — PrintWriter
PrintWriter out = new PrintWriter(socket.getOutputStream()); // ← ?
// Bug 2 — sending a 405 with no body
exchange.sendResponseHeaders(405, 0); // ← ?
// Bug 3 — method check then continue without return
if (!method.equals("POST")) {
exchange.sendResponseHeaders(405, -1);
// ← missing something here!
}
String json = "{ \"status\": \"success\" }";
exchange.sendResponseHeaders(200, json.length()); // ← headers already sent!
Bug 1: What is wrong with new PrintWriter(socket.getOutputStream())?
true, auto-flush is off. Messages pile up in a buffer and the client never receives them.true for auto-flush: new PrintWriter(socket.getOutputStream(), true)Bug 2: Why is sendResponseHeaders(405, 0) wrong for a no-body response?
-1 means "no body at all". 0 means "I will send exactly 0 bytes" — then the client waits for those bytes forever.-1 = no body. 0 = body coming but with 0 bytes → client hangs waiting. Always use -1 for empty responses.Bug 3: What is the missing statement after sending the 405?
return;, execution falls through to the success code — then crashes because headers were already sent.return; after the 405. Without it, the code falls through and tries to send a 200 too — runtime crash.Q4 (Comprehensive): Which of the following correctly describes the three-step response pattern in HttpServer?
Course Complete!
You've mastered Java Socket Servers and HTTP Servers — from raw TCP streams to routing, headers, and JSON responses. You're ready for the exam.