Which socket timeout controls stop a blocking socket.socket.recv from wedging a worker forever?
answer
- The default has no deadline at all
- Three modes, not two
- Zero seconds is a different mode entirely
- settimeout raises rather than returning
- Since 3.10 socket.timeout is just TimeoutError
basics
~10 sCall settimeout(seconds) so recv raises TimeoutError instead of blocking indefinitely. settimeout(None) restores plain blocking mode, and settimeout(0) or setblocking(False) makes calls raise BlockingIOError at once. socket.setdefaulttimeout sets the default for sockets created afterwards.
solid answer
~50 sA socket is in exactly one of **three modes**. Blocking, the default, waits forever — a `recv` on a peer that has gone silent without closing will hang the worker until the process is killed. **Timeout mode**, set with `sock.settimeout(5)`, still blocks, but raises `TimeoutError` once the deadline passes; since Python 3.10 `socket.timeout` is simply an alias of the builtin `TimeoutError`. **Non-blocking mode**, `setblocking(False)` — identical to `settimeout(0)` — never waits and raises `BlockingIOError` when the call cannot complete now. On the client side, `socket.create_connection(addr, timeout=5)` sets the timeout before connecting, so it covers both the connect attempt and later reads unless you change it. `socket.setdefaulttimeout(5)` is a blunt global default for every socket created afterwards, including inside libraries. Two operational caveats: name resolution happens before the timeout applies, so a slow DNS server can still stall you, and a timed-out `sendall` leaves an unknown number of bytes delivered, so the connection must be discarded rather than reused.
code
python · 12 linesimport socket
srv = socket.create_server(("127.0.0.1", 0))
srv.settimeout(0.5)
try:
srv.accept()
except TimeoutError as exc:
print("gave up:", type(exc).__name__)
print("alias since 3.10:", socket.timeout is TimeoutError)
print("gettimeout:", srv.gettimeout())
srv.close()go deeper
Know that a socket blocks forever by default and that settimeout(seconds) makes it raise TimeoutError instead. Setting a timeout on every client socket you create is the habit to build.
Distinguish the three modes cleanly: blocking, timeout and non-blocking, with setblocking(False) equal to settimeout(0). Be able to say which exception each mode produces and what gettimeout reports.
Show the production reasoning: a missing timeout starves a worker pool silently, a timeout is per operation rather than per exchange, a timed-out sendall leaves delivery unknown so the connection must be discarded, and idle dead peers need keepalives or heartbeats.
Own the policy across services: where deadlines are set and budgeted end to end, how retries stay safe when delivery is ambiguous, and how connection age and health checks are standardised so no team rediscovers the hanging worker.
**Why this question is asked at senior level.** The default socket is blocking with no deadline, so the failure it produces is not an exception but the absence of one. Consider a payroll importer that reads a CSV, sends each batch of rows to a downstream service over a socket, and runs behind a queue that peaks around 1,200 requests per minute. If the downstream host is unplugged rather than shut down, no FIN and no RST ever arrive: the connection simply stops producing data. A `recv` with no timeout waits on it forever. The worker never crashes, never logs, never returns its row batch, and the incident presents as a slowly starving pool with a growing backlog — the hardest shape of outage to diagnose, and one line of setup prevents it. **The three modes precisely.** - *Blocking* (`settimeout(None)`, the default): `recv`, `send`, `accept` and `connect` wait as long as the operating system takes. `sock.gettimeout()` returns `None`. - *Timeout* (`settimeout(seconds)`): the call still blocks, but when the deadline passes it raises `TimeoutError`. `gettimeout()` returns the float you set. This is the mode almost every application wants. - *Non-blocking* (`setblocking(False)`, exactly equivalent to `settimeout(0)`): the call returns immediately or raises `BlockingIOError`. `gettimeout()` returns `0.0`. This mode exists so a readiness loop can drive many sockets from one thread; on its own it is not a timeout, it is a different programming model. A common confusion is treating timeout mode and non-blocking mode as the same thing. They are not: timeout mode is still synchronous and still blocks, it merely has a deadline. **Which timeout covers what.** `settimeout` applies per socket operation, not to a whole exchange. A five-second timeout does not bound a conversation to five seconds; it bounds each individual `recv`, `send` or `accept`. A peer that dribbles one byte every four seconds will keep a reader alive indefinitely without ever tripping the timeout, so protocols that must bound total time need their own deadline — record a monotonic start time and check it around the read loop. `socket.create_connection(address, timeout=...)` sets the timeout on the socket *before* calling connect, so it bounds the connect attempt and, because the setting persists, later operations too. What it does not bound is the name resolution that precedes the connect: `getaddrinfo` can block past your timeout when a DNS server is unreachable. Since Python 3.11, `create_connection(..., all_errors=True)` raises an `ExceptionGroup` containing every failed attempt instead of only the last one, which matters when a host resolves to several addresses and only some are reachable. `socket.setdefaulttimeout(seconds)` sets the timeout that newly created sockets start with, and `socket.getdefaulttimeout()` reads it. It is blunt — it reaches sockets created inside third-party code you do not control — which makes it both a useful safety net at process start and a poor place to encode a specific policy. **What to do when a timeout fires.** For `recv`, nothing was consumed and you may in principle retry, but at that point you usually know less about the peer than you would like, and closing is the honest response. For `sendall`, the documentation is explicit that on timeout it is unspecified how much data was sent: the stream offset is unknown, so the connection must be closed rather than reused. In the payroll importer that is precisely the partial-failure rollback question — the downstream may have received all, some, or none of the batch. The design answer lives above the socket: send batches with an idempotency key or a monotonically increasing batch number the receiver de-duplicates on, so a retry after an ambiguous timeout is safe by construction. Recording the last acknowledged batch, and resuming from it, turns "we do not know what got through" into a resumable position. **Detecting the silently dead peer.** A timeout catches a stall on a call you are making. It cannot notice a peer that died while you were idle. `sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)` asks the kernel to probe an idle connection and eventually fail it, though the default idle interval is measured in hours and the tuning knobs are platform-specific. For a pool of long-lived connections, an application-level heartbeat plus a maximum connection age is more predictable than relying on the kernel's defaults. **Where the mode belongs.** Set the timeout once, at construction, next to the connect — not scattered through the read loop where a code path can miss it. Sockets handed to you by a library are the ones to check first, since they usually arrive in the default blocking mode with no deadline at all.
- How does timeout mode differ from non-blocking mode on a socket?Timeout mode still blocks the calling thread; it just gives up after the deadline and raises `TimeoutError`. Non-blocking mode never waits at all: if the operation cannot complete immediately it raises `BlockingIOError`, which is why it is only useful under a readiness loop that tells you when to retry. `setblocking(False)` and `settimeout(0)` are the same thing, and `settimeout(None)` returns the socket to plain blocking mode.
- Does socket.create_connection(addr, timeout=3) bound the whole operation to three seconds?No, in two ways. It sets the socket's timeout before connecting, so it bounds the connect attempt and each later operation individually, not the total. And it does not bound the name resolution that happens first — `getaddrinfo` can block well past three seconds against an unreachable DNS server. If a hard end-to-end deadline matters, track elapsed time yourself with a monotonic clock and resolve names with your own bound.
- A five-second timeout is set, yet a worker still reads from one peer for minutes. How?The timeout applies per operation, not per exchange. A peer that sends a byte every four seconds resets the clock on every `recv`, so the read loop never trips the deadline — the slow-drip pattern behind slowloris-style stalls. Bound the whole message: record a monotonic start time, check it around each read, and cap both the total bytes and the total duration a single message may consume.
Blocking mode is holding a phone to your ear until someone speaks; timeout mode is hanging up after five seconds of silence; non-blocking mode is picking up, hearing nothing, and putting the handset straight back down.
saying these in an interview costs you the question
- Believes sockets have a sensible default timeout
- Confuses non-blocking mode with a timeout
- Expects recv to return None when a timeout expires
- Thinks one settimeout bounds the whole exchange
- Retries on the same socket after a sendall timeout
- Assumes a timeout detects a peer that died while idle