Demystifying Socket I/O: From Creation to Blocking in TCP Communication
This article explains the fundamentals of I/O, details how sockets are created, bound, listened to, and accepted, describes the client-side connect process, and clarifies why read, write, accept, and connect operations can block, laying the groundwork for deeper Netty studies.
I/O Basics
I/O stands for input and output. Disk I/O refers to data transfer between disk and memory, while network I/O involves data movement between the network card and memory. All I/O ultimately interacts with memory because CPU‑memory communication is far faster than CPU‑device communication.
In short, I/O is the exchange of data between memory and external devices.
Creating a Socket
On the server side, a socket is created using the int socket(int domain, int type, int protocol); function. The parameters are:
domain – selects the protocol family (e.g., IPv4 or IPv6).
type – selects the socket type (e.g., stream or datagram).
protocol – specifies the protocol; usually set to 0 to let the system infer it.
Example: socket(AF_INET, SOCK_STREAM, 0); creates an IPv4 TCP stream socket. The function returns an integer file descriptor (fd) representing the socket.
bind()
After creating a socket,
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);assigns an IP address and port to the socket, making it reachable by clients.
listen()
Calling int listen(int sockfd, int backlog); puts the socket into a passive listening state. The backlog parameter defines the size of the queue that holds pending connections. Different interpretations exist:
A single queue stores both completed and half‑open connections; backlog is its size.
Two queues are used (completed and half‑open); backlog is the sum of both.
Two queues are used, but backlog only limits the completed‑connection queue.
accept()
When a client connects, the completed connection is placed in the completed‑connection queue. The server retrieves it with
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);, which returns a new file descriptor for the established connection. If the queue is empty, accept blocks until a connection arrives.
Client connect()
The client also creates a socket with socket() and then initiates a TCP three‑way handshake using
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);. After sending SYN, the socket enters the SYN_SEND state; upon receiving SYN+ACK, it moves to ESTABLISHED, completing the handshake.
The client does not need to call bind; the system selects a source IP and an ephemeral port automatically.
read() and write()
Once a connection is established, data is exchanged via read and write. Both operations can block: read waits for incoming data, while write may block if the TCP send buffer is full or flow control pauses transmission.
Why Network I/O Blocks
Why does network I/O become blocking?
Methods such as accept, connect, read, and write may block, occupying the executing thread and reducing performance. The early solution was to spawn many threads, which led to the C10K problem as connection counts grew. This motivated the development of non‑blocking sockets, I/O multiplexing, signal‑driven I/O, and asynchronous I/O models.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
