Network Sockets
debt(d7/e5/b5/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints.tools list (strace, lsof, netstat, ss) are runtime diagnostic tools, not static analyzers. Socket misuse like missing timeouts, leaked descriptors, or partial write handling are not caught at compile time or by standard linters - they manifest as runtime failures (hangs, resource exhaustion, data corruption). The code_pattern regex could catch some issues but detection_hints.automated is 'no'.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix mentions setting timeouts, closing in finally blocks, and looping on partial writes - these are not single-line patches but require systematic changes across all socket usage. If an application has scattered socket code without proper timeout/cleanup patterns, fixing requires refactoring each usage site, potentially introducing wrapper abstractions.
Closest to 'persistent productivity tax' (b5). Socket programming applies across web/cli/queue-worker contexts per applies_to, meaning the complexity reaches across the system. The common_mistakes around TIME_WAIT, partial writes, and stream framing impose ongoing cognitive load on maintainers. However, most PHP applications use higher-level abstractions (curl, PDO) rather than raw sockets, limiting the burden to specific use cases rather than defining the entire architecture.
Closest to 'serious trap - contradicts how similar concept works elsewhere' (t7). The misconception field explicitly states developers confuse sockets with TCP connections. Additionally, common_mistakes reveals the critical trap that 'one send equals one recv' - TCP stream semantics contradict the intuitive packet-based mental model most developers bring from UDP or message queues. Assuming writes complete fully also contradicts typical file I/O behavior where partial writes are rare.
Also Known As
TL;DR
Explanation
A socket is an operating system abstraction representing one endpoint of a two-way communication link between programs running on a network. Sockets sit between your application code and the TCP/IP stack, providing a file-descriptor-like interface for sending and receiving data. The socket API (originally Berkeley sockets from 4.2BSD) is the foundation for all network programming - when PHP's curl fetches a URL, when your application connects to MySQL, or when nginx accepts HTTP requests, sockets are the underlying mechanism. Key concepts: a socket is identified by protocol (TCP/UDP), local address, local port, remote address, and remote port. Stream sockets (SOCK_STREAM) provide reliable, ordered, connection-oriented communication over TCP. Datagram sockets (SOCK_DGRAM) provide connectionless, unreliable communication over UDP. The lifecycle involves socket creation, binding to an address/port, listening (for servers), connecting (for clients), reading/writing data, and closing. PHP exposes sockets through the socket extension (low-level) and stream wrappers (high-level). Understanding sockets explains connection pooling, why 'address already in use' errors occur, how load balancers distribute traffic, and why non-blocking I/O matters for concurrent servers.
Diagram
flowchart TD
subgraph Server
S1[socket] --> S2[bind]
S2 --> S3[listen]
S3 --> S4[accept]
S4 --> S5[read/write]
S5 --> S6[close]
end
subgraph Client
C1[socket] --> C2[connect]
C2 --> C3[read/write]
C3 --> C4[close]
end
S4 -.->|TCP handshake| C2
S5 <-.->|Data exchange| C3
style S1 fill:#1f6feb,color:#fff
style C1 fill:#238636,color:#fff
style S4 fill:#d29922,color:#fff
style C2 fill:#d29922,color:#fff
Common Misconception
Why It Matters
Common Mistakes
- Not closing sockets properly - leaked file descriptors exhaust system limits and cause 'too many open files' errors.
- Ignoring TIME_WAIT state - rapidly opening and closing connections to the same port causes 'address already in use' because the OS holds the socket for 2*MSL (typically 60 seconds).
- Blocking reads without timeouts - a misbehaving remote host can hang your application indefinitely if you do not set socket timeouts.
- Assuming one send equals one recv - TCP is a stream protocol; data may arrive in different chunk sizes than sent, requiring application-level message framing.
- Not handling partial writes - socket_write may send fewer bytes than requested; you must loop until all data is sent.
Avoid When
- High-level abstractions suffice - use Guzzle, curl, or PDO instead of raw sockets for HTTP and database connections.
- You need portable code across environments - socket extension availability varies; stream functions are more portable.
- Simple request-response patterns - stream_socket_client with stream wrappers is simpler for basic TCP/UDP communication.
When To Use
- Building custom protocol servers - raw sockets give full control over connection handling and data framing.
- Implementing non-blocking I/O - socket_select enables multiplexing multiple connections in a single process.
- Performance-critical network code - raw sockets avoid abstraction overhead when handling thousands of connections.
- Learning network fundamentals - socket programming reveals how HTTP, databases, and other protocols work under the hood.
Code Examples
<?php
// No timeout - blocks forever if remote host is unresponsive:
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, '10.0.0.1', 8080);
$data = socket_read($socket, 1024); // Hangs indefinitely
// Assuming full write completes:
socket_write($socket, $largePayload); // May only send partial data
// Leaking socket - no close on error path:
if ($data === false) {
throw new Exception('Read failed');
// $socket never closed - file descriptor leak
}
<?php
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
throw new RuntimeException('socket_create failed: ' . socket_strerror(socket_last_error()));
}
try {
// Set timeouts to prevent indefinite blocking:
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ['sec' => 5, 'usec' => 0]);
socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, ['sec' => 5, 'usec' => 0]);
if (!socket_connect($socket, '10.0.0.1', 8080)) {
throw new RuntimeException('Connect failed: ' . socket_strerror(socket_last_error($socket)));
}
// Handle partial writes:
$toSend = $largePayload;
while (strlen($toSend) > 0) {
$sent = socket_write($socket, $toSend);
if ($sent === false) {
throw new RuntimeException('Write failed');
}
$toSend = substr($toSend, $sent);
}
$data = socket_read($socket, 1024);
} finally {
socket_close($socket); // Always close, even on error
}