Skip to main content

Lib/socket.py

cpython 3.14 @ ab2d84fe1023/Lib/socket.py

Lib/socket.py is the Python-side half of the socket module. The real socket type (socket.socket) and all address-family constants originate in Modules/socketmodule.c, which is imported as _socket. The Python module re-exports everything from _socket, then adds pure-Python helpers: create_connection, create_server, makefile, socketpair, fromfd, and fromshare.

socket.socket subclasses _socket.socket and overrides __init__, __enter__, __exit__, __repr__, and makefile so that the file-like wrapper returned by makefile() holds a reference to the socket and closes it correctly. The setblocking and settimeout methods are thin Python wrappers that translate the timeout value into a _socket call.

Constants (AF_*, SOCK_*, IPPROTO_*, SOL_*, SO_*, SHUT_*) are imported wholesale from _socket via from _socket import *.

Map

LinesSymbolRolegopy
1-100Imports, __all__, re-export from _socketPulls every constant and the low-level socket type out of _socket; defines the Python socket class that subclasses it.(stdlib pending)
100-200socket.__init__, socket.connect, socket.bind, socket.listen, socket.acceptLifecycle methods; accept returns a (socket, address) pair where the new socket is wrapped in the Python socket subclass.(stdlib pending)
200-400create_connection, create_servercreate_connection iterates getaddrinfo results and connects to each in turn with an optional timeout; create_server binds and listens with SO_REUSEADDR and optional SO_REUSEPORT.(stdlib pending)
400-600getaddrinfo, getnameinfoThin pass-throughs to _socket.getaddrinfo / _socket.getnameinfo; documented here for the type-narrowing and default-flag annotations added at the Python level.(stdlib pending)
600-800socket.makefile, socket.setblocking, socket.settimeout, socket.getblocking, socket.gettimeoutmakefile wraps the socket in a SocketIO object and then in a BufferedReader/BufferedWriter; the timeout methods translate between Python's None/float and the C-level timeout representation.(stdlib pending)
800-1000socketpair, fromfd, fromshare, has_dualstack_ipv6, timeout exceptionsocketpair creates a connected pair via _socket.socketpair and wraps both ends; fromfd duplicates a raw file descriptor into a managed socket; has_dualstack_ipv6 probes at import time.(stdlib pending)

Reading

create_connection with timeout (lines 200 to 400)

cpython 3.14 @ ab2d84fe1023/Lib/socket.py#L200-400

def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
source_address=None, *,
all_errors=False):
host, port = address
exceptions = []
for res in getaddrinfo(host, port, 0, SOCK_STREAM):
af, socktype, proto, canonname, sa = res
sock = None
try:
sock = socket(af, socktype, proto)
if timeout is not _GLOBAL_DEFAULT_TIMEOUT:
sock.settimeout(timeout)
if source_address:
sock.bind(source_address)
sock.connect(sa)
exceptions.clear()
return sock
except error as exc:
if not all_errors:
exceptions = [exc]
else:
exceptions.append(exc)
if sock is not None:
sock.close()
if len(exceptions) == 1:
raise exceptions[0]
else:
# if multiple exceptions occurred, format the messages
model = exceptions[0]
raise ExceptionGroup(
"create_connection failed", exceptions) from model

create_connection iterates the full getaddrinfo result list so it handles both IPv4 and IPv6 transparently. It closes each failed socket immediately to avoid descriptor leaks before trying the next address. When all_errors=False (the default) only the last exception is propagated; setting all_errors=True collects all of them into an ExceptionGroup. The sentinel _GLOBAL_DEFAULT_TIMEOUT is distinct from None so that callers can explicitly pass None to mean "no timeout" without silently inheriting the global default.

getaddrinfo result iteration (lines 400 to 600)

cpython 3.14 @ ab2d84fe1023/Lib/socket.py#L400-600

results = socket.getaddrinfo(host, port, proto=IPPROTO_TCP)
for family, type, proto, canonname, sockaddr in results:
# family: AF_INET or AF_INET6
# sockaddr: (ip, port) for AF_INET
# (ip, port, flowinfo, scope_id) for AF_INET6
print(family, sockaddr)

getaddrinfo returns a list of 5-tuples. The sockaddr element differs by address family: (host, port) for AF_INET and (host, port, flowinfo, scope_id) for AF_INET6. Callers that pass sockaddr directly to connect() or bind() do not need to unpack it because the C layer accepts both forms.

makefile buffered I/O bridge (lines 600 to 800)

cpython 3.14 @ ab2d84fe1023/Lib/socket.py#L600-800

def makefile(self, mode="r", buffering=None, *,
encoding=None, errors=None, newline=None):
for c in mode:
if c not in {"r", "w", "b"}:
raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,))
writing = "w" in mode
reading = "r" in mode or not writing
assert reading or writing
binary = "b" in mode
rawmode = ""
if reading:
rawmode += "r"
if writing:
rawmode += "w"
raw = SocketIO(self, rawmode)
self._io_refs += 1
if buffering is None:
buffering = -1
if buffering < 0:
buffering = io.DEFAULT_BUFFER_SIZE
if buffering == 0:
if not binary:
raise ValueError("unbuffered streams must be binary")
return raw
if reading and writing:
buffer = io.BufferedRWPair(SocketIO(self, "r"),
SocketIO(self, "w"), buffering)
elif reading:
buffer = io.BufferedReader(raw, buffering)
else:
buffer = io.BufferedWriter(raw, buffering)
if binary:
return buffer
return io.TextIOWrapper(buffer, encoding, errors, newline)

SocketIO is a RawIOBase that delegates readinto and write to the socket. makefile layers io.Buffered* on top of it and optionally wraps that in TextIOWrapper. The _io_refs counter tracks how many file objects hold a reference to the socket; socket.close() defers the actual _socket.close() call until _io_refs reaches zero, preventing "bad file descriptor" errors when the file wrapper outlives an explicit socket close.

gopy mirror

Lib/socket.py is a prerequisite for smtplib, http.client, ftplib, urllib, and many other network modules. The C extension _socket must provide the raw socket type and all constants. The pure-Python layer (create_connection, create_server, makefile) can be ported once _socket is available. SocketIO belongs to Lib/socket.py and must be ported alongside makefile.