Socket options and the exception family
◈ 6 cardsSet the options that actually change behaviour — SO_TIMEOUT first, then TCP_NODELAY, SO_LINGER, the buffers and SO_KEEPALIVE — and diagnose a failed connection from its exception subclass.
Nine options, one that always matters
Java exposes nine options on a client socket, and their odd names come straight from the Berkeley Unix C headers where sockets were invented: TCP_NODELAY, SO_BINDADDR, SO_TIMEOUT, SO_LINGER, SO_SNDBUF, SO_RCVBUF, SO_KEEPALIVE, OOBINLINE and IP_TOS. Most are reached through a getter/setter pair on Socket with a normal Java name — SO_BINDADDR is read-only, exposed as getLocalAddress() — and each throws SocketException if the platform's socket implementation cannot honour it.
SO_TIMEOUT is the one you set every time. setSoTimeout(ms) bounds each read; 0 is the default and means block forever. When it expires you get a SocketTimeoutException and — this is the useful part — the socket stays connected, so you may retry the read. It is the difference between a client that reports a problem and a client that hangs.
Nagle, and when to turn it off
Nagle's algorithm is on by default. It coalesces small writes: rather than putting a one-byte payload in its own packet, TCP holds it until the previous packet is acknowledged, then sends whatever accumulated. On bulk transfers this is pure win — fewer packets, less header overhead.
It is a loss when your protocol is a stream of small, latency-sensitive parcels: a game sending cursor positions, a terminal session, an interactive request/response protocol on a slow link. Every small write waits for a round trip that carries no data. setTcpNoDelay(true) turns TCP_NODELAY on, which turns the coalescing off and sends each write immediately. Note the double negative; it is a common exam trip.
Lingering, buffers, keepalives, and the rest
SO_LINGER decides what close() does with data still queued. By default close() returns at once and the TCP stack keeps trying to deliver. setSoLinger(true, 0) discards unsent data immediately. setSoLinger(true, n) makes close() block up to n seconds waiting for delivery and acknowledgment. The maximum is 65,535 seconds, and getSoLinger() returns -1 when the option is off.
SO_RCVBUF and SO_SNDBUF (setReceiveBufferSize / setSendBufferSize) are hints to the stack. They matter because maximum throughput is roughly buffer size divided by round-trip latency, so a high-latency link needs a large buffer to go fast — a fat transcontinental pipe with a small buffer stays slow no matter how much bandwidth it has. 128 KB is a common modern default.
SO_KEEPALIVE (default false) sends a probe over an idle connection, typically every two hours, so a client eventually notices a peer that died without closing. OOBINLINE governs TCP's single-byte urgent data (sendUrgentData), which Java discards by default and almost no protocol uses. IP_TOS (setTrafficClass) sets the eight-bit class-of-service field — six bits of DSCP plus two of ECN — that routers may use to prioritise, and frequently ignore. SO_REUSEADDR exists on Socket but earns its keep on the server side, in Module 7.
Diagnose from the exception type
Most Socket methods throw IOException or its subclass SocketException, and knowing only "something failed" is not enough to act. The subclasses answer which thing failed:
BindException— the local port is already in use, or you lack the privilege to bind it (ports below 1024).ConnectException— the remote host actively refused: nothing is listening on that port, or its backlog is full.NoRouteToHostException— the attempt timed out; the host is down, or a firewall is silently dropping your packets.ProtocolException— extendsIOExceptiondirectly, notSocketException; the peer sent something that violates the specification.SocketTimeoutException— extendsInterruptedIOException, so it is not aSocketException. Catch it before or alongside, never expecting aSocketExceptionclause to cover it.
Worked example — a client that says what actually went wrong
A catch (IOException ex) that prints "network error" is worthless to whoever has to fix it. Catch the subclasses most-specific first and turn each into an instruction: refused means check the port and whether the service is up; no route means check the host and the firewall; a read timeout means the server accepted you and then stalled. Same code, three different next actions.
source Harold 4e ch8 §Socket Exceptions; JDK javadoc java.net.SocketTimeoutException