接續上篇 Client 端,本文詳細拆解 Server 端的四大核心階段:Socket 創建 → 綁定監聽 → 循環接受 → 數據交互,基於經典 Unix 網絡編程模型,代碼經 CentOS 實測驗證。
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main() {
int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
// ...
unlink("server_socket"); // 本地文件 socket 清理(若用 AF_UNIX)
server_sockfd = socket(AF_INET, SOCK_STREAM, 0); // IPv4, TCP
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY); // 0.0.0.0 監聽所有網卡
server_address.sin_port = htons(9734); // 端口 9734
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr*)&server_address, server_len); listen(server_sockfd, 5); // 積壓隊列長度 5
while (1) {
char ch;
printf("server waiting\n");
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,
(struct sockaddr*)&client_address,
&client_len);
read(client_sockfd, &ch, 1); // 讀 1 字節
ch++; // 業務邏輯:字元 +1
write(client_sockfd, &ch, 1); // 寫回
close(client_sockfd); // 關閉客戶端連接,繼續等待下一個
}
| 階段 | Client | Server |
|---|---|---|
| 1. 創建 | socket() | socket() |
| 2. 綁定 | 無 (隱式) | bind() |
| 3. 監聽 | 無 | listen() |
| 4. 連接 | connect() | accept() (阻塞等待) |
| 5. 數據交互 | read/write | read/write |
| 6. 關閉 | close() | close(client_sockfd) + 循環 |
server_sockfd 只負責「聽門」,client_sockfd 專用於與特定客戶端通信,支持併發處理多客戶端(需 fork/thread/epoll)。accept、read、write 均為阻塞調用。Address already in use,需設置 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))。SIGCHLD 回收僵屍進程,或設置 SA_NOCLDWAIT。fork() 或 pthread_create())。SIGINT,關閉 server_sockfd 退出循環。select() 實現單進程多路復用 Server。Server 端的核心模式是 「一個監聽 Socket + 循環 Accept + 為每連接創建專用 Socket」。掌握這一模式,是理解 Nginx/Redis 等高性能服務器「Reactor 模式」的基石。建議在 Linux 終端親手編譯運行,觀察 netstat -anp 端口狀態變化,體會「一切皆文件」的 Unix 哲學。