W3docs

Java Sockets

Open TCP client connections in Java with the Socket class.

Beneath HTTP and every other application protocol sits the socket: a raw, bidirectional TCP connection between two endpoints. Java's java.net.Socket is the client side — you create one, connect it to a host and port, and then read and write bytes through ordinary InputStream/OutputStreams. This is the lowest-level networking you reach for when you speak a custom protocol or talk to a service that is not HTTP.

This chapter covers what a connected socket gives you, the two ways to connect (and why one is safer), how to read and write text and raw bytes, a complete runnable client-talks-to-server example, the timeouts and gotchas that bite real code, and where sockets fit relative to the higher-level HttpClient you have already met.

What a Socket gives you

A connected Socket is a pipe with two streams:

  • socket.getOutputStream() — bytes you write travel to the other end.
  • socket.getInputStream() — bytes the other end writes arrive here.

TCP guarantees the bytes arrive reliably and in order. It does not impose any message structure — a socket is a stream of bytes, not of messages. Framing (where one message ends and the next begins) is your job: use newlines, length prefixes, or a higher-level protocol. If you need message boundaries preserved instead of a stream, that is the job of datagram (UDP) sockets, which trade ordering and reliability for discrete packets.

The streams come straight from Java's I/O system: getInputStream() returns a plain InputStream and getOutputStream() a plain OutputStream, so every wrapper you know — BufferedReader, PrintWriter, DataInputStream — works over a socket exactly as it does over a file.

Connecting

// Style 1: connect in the constructor
Socket socket = new Socket("example.com", 80);

// Style 2: create then connect with a timeout (preferred)
Socket socket = new Socket();
socket.connect(new InetSocketAddress("example.com", 80), 2000);

The second form lets you set a connect timeout — without it, an unreachable host can hang the thread for the OS default (often a minute or more). Once connected, wrap the streams in buffered readers/writers and pick a character set explicitly.

Reading and writing text

var out = new PrintWriter(
        new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true);
var in = new BufferedReader(
        new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));

out.println("ping");                 // autoFlush=true sends it immediately
String reply = in.readLine();        // blocks until a line arrives

readLine() blocks until data (or end-of-stream) arrives — the hallmark of the classic blocking socket API. Always close the socket (try-with-resources) to release the connection.

Reading raw bytes

Text is convenient, but many protocols are binary — image data, length-prefixed frames, a custom wire format. There, skip the readers and work with the streams directly:

try (Socket socket = new Socket()) {
    socket.connect(new InetSocketAddress("example.com", 80), 2000);
    OutputStream out = socket.getOutputStream();
    InputStream in = socket.getInputStream();

    out.write("PING".getBytes(StandardCharsets.UTF_8));
    out.flush();                          // streams are not auto-flushed

    byte[] buffer = new byte[4096];
    int n = in.read(buffer);              // bytes read, or -1 at end-of-stream
    if (n > 0) {
        String chunk = new String(buffer, 0, n, StandardCharsets.UTF_8);
        System.out.println(chunk);
    }
}

Two facts shape every byte-level read:

  • read(byte[]) returns how many bytes it actually got, which is not necessarily what you asked for. One write on the other end can arrive as several reads, and several writes can arrive as one read — TCP coalesces and splits at will. To get a fixed number of bytes you must loop, or wrap the stream in DataInputStream and call readFully().
  • A return value of -1 means the peer closed its end (end-of-stream), not "no data right now." That is your signal to stop reading.

Timeouts that matter

A blocking socket can stall in two distinct places, and they need two distinct timeouts:

Socket socket = new Socket();
socket.connect(new InetSocketAddress("example.com", 80), 2000); // connect timeout
socket.setSoTimeout(5000);                                       // read timeout
  • The connect timeout (the second argument to connect) caps how long the TCP handshake may take. Without it, an unreachable host hangs the thread for the OS default — often a minute or more.
  • The read timeout (setSoTimeout) caps how long any single read/readLine may block waiting for data. When it expires, the call throws SocketTimeoutException without closing the socket, so you can decide whether to retry or give up. Without it, a silent peer blocks you forever.

Real network code should set both. The two errors you must be ready to catch are UnknownHostException (DNS could not resolve the name) and the broad IOException family (connection refused, reset, or timed out); see Java exceptions for handling patterns.

A worked example: a client talking to a loopback echo server

This program starts a one-shot echo server on a background thread bound to the loopback address, then — the chapter's real focus — connects a client Socket, sends a line, and reads the reply. It is a complete TCP conversation inside one JVM, no external network.

java— editable, runs on the server

What to take from the run:

  • The client side is just three steps: construct a Socket, connect() it to an address and port, then read and write its streams. Everything HTTP did for you in earlier chapters — request lines, headers, status codes — is gone; a socket moves raw bytes and nothing more.
  • connect(new InetSocketAddress(...), 2000) set a 2-second connect timeout. The no-timeout constructor new Socket(host, port) would block on the OS default if the host were unreachable, so the explicit-timeout form is the safer habit for any real network.
  • The protocol was a convention, not a feature: the client wrote one line and read one line because both sides agreed that lines are messages. TCP delivered an ordered byte stream; the newline framing that turned it into "messages" was entirely application-defined.
  • readLine() blocked until the server's reply arrived. This thread-per-connection, block-until-data model is simple and correct, and it is exactly the cost that virtual threads aim to make cheap when connection counts grow large.
  • getRemoteSocketAddress() and getLocalSocketAddress() showed both ends of the live connection — the server's loopback port and the client's OS-assigned local port. Every TCP connection is identified by that pair of endpoints. The server-side ServerSocket builds the listener that accepted this connection.

When to reach for a raw socket

A Socket is the right tool when there is no library that already speaks your protocol:

  • You are implementing or consuming a custom TCP protocol (a game server, a message broker wire format, a line-based admin port).
  • You need to talk to a non-HTTP service — SMTP, a Redis-style text protocol, a legacy line server.

For anything that is HTTP, do not hand-roll requests over a socket. Use the modern HttpClient, which gives you connection pooling, redirects, HTTP/2, and TLS for free. The relationship is the same as between raw byte streams and the higher-level readers built on top of them: drop to the lower level only when the higher one cannot express what you need.

Practice

Practice
A client reads from a server using 'socket.getInputStream()' wrapped in a 'BufferedReader', sending one newline-terminated command and expecting one newline-terminated reply. Occasionally a reply is split across two TCP segments and the client misreads it. What is the correct understanding?
A client reads from a server using 'socket.getInputStream()' wrapped in a 'BufferedReader', sending one newline-terminated command and expecting one newline-terminated reply. Occasionally a reply is split across two TCP segments and the client misreads it. What is the correct understanding?
Was this page helpful?