Socket 是應用層訪問網絡協議棧的標準 API,屏蔽了 OSI 會話層以下的路由、傳輸細節。掌握 Socket 類型選型、核心 API 語義及典型漏洞,是後端工程師構建高可靠網絡服務的必修功課。
| 維度 | Stream Socket (SOCK_STREAM) | Datagram Socket (SOCK_DGRAM) |
|---|---|---|
| 協議 | TCP (IPPROTO_TCP) | UDP (IPPROTO_UDP) |
| 連接模式 | 面向連接,三次握手建立雙向可靠流 | 無連接,單向不可靠數據報 |
| 數據邊界 | 無邊界,字節流 (需應用層分幀) | 保留邊界,每次 sendto/recvfrom 一個報文 |
| 可靠性 | 序號、ACK、重傳、流控、擁塞控制保證有序不重不丟 | 無保證,可能丟包、亂序、重複 |
| 開銷 | 頭部 20+ 字節,連接狀態機,系統開銷大 | 頭部 8 字節,無狀態,輕量 |
| 典型場景 | Web/HTTP、郵件/SMTP、SSH、資料庫、即時通訊核心邏輯 | DNS、NTP、流媒體/RTP、遊戲狀態同步、廣播發現 |
| 編程複雜度 | 需處理粘包/拆包、背壓、半關閉 | 需應用層實現 ACK/重傳/排序 (如 QUIC/KCP) |
// 1. 創建 Socket
int sockfd = socket(int domain, int type, int protocol);
// domain: AF_INET(IPv4), AF_INET6(IPv6), AF_UNIX(本地)
// type: SOCK_STREAM, SOCK_DGRAM, SOCK_RAW...
// 返回文件描述符,失敗 -1
// 2. 客戶端發起連接
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
// 成功 0,失敗 -1 (errno: ECONNREFUSED, ETIMEDOUT...)
// 3. 服務端綁定、監聽
bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(sockfd, backlog); // backlog: 內核待接受隊列長度
// 4. 接受連接 (阻塞直到新連接到達)
int connfd = accept(int sockfd, struct sockaddr *cli_addr, socklen_t *addrlen);
// 返回**新**文件描述符代表此連接,原 sockfd 繼續監聽
// 5. 數據收發
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
// 返回實際收發字節數,0 表示對端關閉 (TCP),-1 失敗
// UDP 使用 sendto/recvfrom 需指定目標地址
PF_INET 2 // IPv4 (最常用)
PF_INET6 10 // IPv6
PF_UNIX 1 // 本地進程間通信 (Unix Domain Socket)
PF_PACKET 17 // 直接鏈路層封裝 (抓包、造包工具)
enum __socket_type {
SOCK_STREAM = 1, // TCP 流
SOCK_DGRAM = 2, // UDP 數據報
SOCK_RAW = 3, // 原始 Socket (需 CAP_NET_RAW)
SOCK_SEQPACKET = 5, // 順序包 (SCTP)
...
};
/proc/sys/net/ipv4/tcp_syncookies=1、增大 somaxconn、部署 WAF/抗 DDoS 設備。recv(sock, buf, sizeof(buf)-1, 0)、編譯器啟用 -fstack-protector-strong -D_FORTIFY_SOURCE=2、地址隨機化 (ASLR)。setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) 避免重啟端口佔用。SO_RCVTIMEO / SO_SNDTIMEO 避免無限阻塞。shutdown(sock, SHUT_WR) 觸發 FIN,再 recv 讀 0 後 close,優雅斷開。Socket 編程看似底層,實則是架構可靠性的基石。從協議選型到參數調優,每一個決策都在為系統的穩健性投票。