Understanding Network Protocols, TCP/UDP Handshakes, and Socket Connection Pools
This article explains the OSI seven‑layer model, the differences between TCP and UDP, the three‑way handshake and four‑step termination processes, long‑living socket connections, heartbeat mechanisms, custom application‑layer protocols, and how to implement a socket connection pool using Node.js.
Preface: Developers often encounter terms like HTTP, TCP/IP, UDP, Socket, long‑living sockets, and socket connection pools, but their relationships and underlying principles are not always clear. This article starts from basic network protocols and gradually explains their connections up to socket connection pools.
OSI Seven‑Layer Model
The OSI (Open System Interconnection) model consists of seven layers from bottom to top: Physical, Data Link, Network, Transport, Session, Presentation, and Application. The diagram below maps common protocols to these layers.
From the diagram, IP belongs to the Network layer, TCP/UDP to the Transport layer, and HTTP to the Application layer. OSI does not define Socket; its details will be introduced later with code examples.
TCP and UDP Connections
TCP is connection‑oriented and reliable, requiring a three‑way handshake, while UDP is connection‑less, faster, but unreliable. The following sections detail TCP’s handshake and termination processes.
TCP Three‑Way Handshake and Four‑Step Termination
During connection establishment, the client sends a SYN, the server replies with SYN‑ACK, and the client finalizes with ACK, moving both sides to the ESTABLISHED state.
Connection termination requires four steps: FIN from the initiator, ACK from the peer, FIN from the peer, and final ACK, after which the initiator stays in TIME_WAIT for 2 MSL to ensure all packets are properly discarded.
TCP vs UDP
TCP provides reliable, ordered delivery with connection management; UDP offers unordered, best‑effort delivery without handshakes.
Because UDP lacks handshakes, its overhead is lower and latency higher, making it suitable for real‑time scenarios despite the lack of built‑in reliability.
Common Questions
1. Maximum concurrent TCP connections: Not limited by the 65535 port range; it depends on system resources such as the maximum number of open file descriptors ( ulimit -n ) and kernel parameters.
2. Why TIME_WAIT lasts 2 MSL: To handle possible loss of the final ACK; the side in TIME_WAIT can retransmit the ACK if needed.
3. Impact of many TIME_WAIT sockets: Each TIME_WAIT consumes a local port; heavy short‑connection traffic can exhaust ports, leading to “address already in use” errors. Adjusting kernel parameters (e.g., net.ipv4.tcp_tw_reuse , net.ipv4.tcp_tw_recycle ) can mitigate the issue.
To apply kernel tweaks, edit /etc/sysctl.conf and run /sbin/sysctl -p :
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30Long‑Living Socket Connections
A long‑living connection allows multiple data packets to be sent over a single TCP socket, often kept alive with heartbeat messages. Short connections open, transmit, and close for each request, which incurs handshake overhead.
Long connections are preferred for frequent, point‑to‑point communication where establishing a new connection each time would degrade performance (e.g., database connections).
Heartbeat Packets
Heartbeat packets are periodic messages that inform the peer of the connection’s liveliness. They help detect broken sockets caused by network failures.
Defining a Custom Application‑Layer Protocol
When building a custom protocol on top of TCP, consider defining a heartbeat format, a message header that includes the payload length, and the serialization format (e.g., JSON).
Example header: length:000000000xxxx where the total header length is 20 bytes.
Socket Connection Pool
A socket connection pool maintains a collection of reusable long‑living sockets, automatically checking their health, discarding invalid ones, and replenishing the pool as needed. The pool typically tracks idle sockets, active sockets, and waiting requests.
When a request arrives, the pool provides an idle socket; if none are available and the pool has not reached its maximum size, a new socket is created; otherwise the request waits.
Node.js Generic‑Pool Example
The following diagram shows the directory structure of a generic‑pool implementation.
Initializing the Pool
Using the Pool
The pool is used with the previously defined custom protocol.
Log output shows that the first two requests establish new sockets; subsequent requests reuse existing sockets from the pool.
Source Code Analysis
The core implementation resides in lib/Pool.js . The constructor defines queues for idle resources, active resources, and waiting requests.
The acquire method handles various scenarios to finally obtain a long‑living socket resource.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
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.