傳統TCP服務器兩極:
本文提出「基於消息隊列的迭代服務器」:**固定3進程 (1守護 + 2通信) 處理無限連接**,結合**非阻塞I/O + 輪詢 + 共享內存連接表 + 消息隊列異步解耦**,實現高併發、低資源、易管理。
+------------------+ 共享內存連接表 +------------------+
| 守護進程 tcp_s | ◄─────────────────────► | 通信進程 tcp_s1 |
| (accept + 登記) | | (接收 + 入隊) |
+------------------+ +--------+---------+
|
消息隊列 qid3
|
+------------------+ +--------v---------+
| 客戶機 tcp_c | ◄── L1 (讀) / L2 (寫) ──► | 通信進程 tcp_s2 |
| (雙連接 + 子進程)| | (出隊 + 發送) |
+------------------+ +------------------+
消息隊列 qid4
accept 初始連接 L0 → 讀取客戶機雙端口 → **登記共享內存** (IP, 端口, 狀態) → **僅首次連接時 fork tcp_s1/tcp_s2** → 循環等待新連接。connect 建立 L1 → 設置 **非阻塞 (O_NDELAY)** → 輪詢所有 L1 read → 讀到數據封裝 msg_buf (含 sid 來源連接號) → msgsnd 入隊 qid3。connect 建立 L2 → msgrcv(IPC_NOWAIT) 非阻塞出隊 qid4 → 依 sid 查共享內存獲取對應 L2 socket → write 發送。listen 兩個端口 (cport1, cport2),服務器主動 connect 回連。**反轉連接方向**,服務器主動發起數據通道建立。SO_SNDBUF=0 (L1) / SO_RCVBUF=0 (L2) 節省內核緩衝區內存。struct s_linkinfo {
int id; // 連接序號 (1-based)
int s_socket1; // L1 socket (讀)
int linkf1; // L1 連接標誌
int cport1; // 客戶機 L1 端口
int s_socket2; // L2 socket (寫)
int linkf2; // L2 連接標誌
int cport2; // 客戶機 L2 端口
u_long client_addr; // 客戶機 IP
char flag; // 'i' 有效 / 'o' 空閒
};
sid,O(1) 訪問。shm_logout 後移數組)。struct msg_buf {
long mtype; // 消息類型 (業務進程用於篩選)
long cpid; // 客戶業務進程 PID
long sid; // 來源/目標連接號 (關鍵路由鍵)
long msgid; // 消息序號 (超時重發/去重)
char mdata[MSGSIZE-16]; // 承載數據
};
c_process 與通信進程 tcp_c/tcp_c1 交換數據。s_process 與通信進程 tcp_s1/tcp_s2 交換數據。sid:tcp_s1 讀到數據 → 填入 sid → 入隊 qid3 → s_process 處理 → 回填 sid → 入隊 qid4 → tcp_s2 依 sid 查 L2 socket → 發送。**實現多連接多路復用,無需業務進程感知網絡細節。**cpid 作為 mtype,c_process 只收自己的回覆,天然隔離。msgid + alarm(20) + SIGALRM 處理超時/去重。fcntl(s, F_SETFL, flags | O_NDELAY) 設置 socket 非阻塞。read 返回 -1 (errno=EAGAIN/EWOULDBLOCK) 表示無數據,**不阻塞**,繼續輪詢下一連接/檢查新連接。msgrcv(..., IPC_NOWAIT) 同理。**這是「迭代服務器」能並發處理的關鍵——事件輪詢循環替代阻塞等待。**select/poll/epoll/kqueue/IOCP 內核級多路復用,效率更高,編程模型同源。listen 兩端口接受服務器回連建立 L1/L2。tcp_c1 專收 L2 → 入隊 qid2;主進程 tcp_c 從 qid1 取數據 → 發 L1。c_process 操作 qid1/qid2,**完全屏蔽網絡細節**。| 原設計 | 現代最佳實踐 |
|---|---|
| System V 消息隊列 (msgget/msgsnd/msgrcv) | **POSIX 消息隊列 (mq_open/mq_send/mq_receive)** 或 **無鎖環形緩衝區 + eventfd** (線程間) / **Redis/RabbitMQ/Kafka** (進程間/分布式) |
| System V 共享內存 (shmget/shmat) | mmap(MAP_SHARED | MAP_ANONYMOUS) (父子進程) / memfd_create / **共享內存對象 (shm_open) |
| fork 多進程 | **線程池 + 非阻塞I/O + epoll/IOCP** (單進程多線程) 或 **多進程 + SO_REUSEPORT** (多核縮放) |
| 信號量同步共享內存 (隱含) | 必須顯式同步:pthread_mutex (進程共享屬性) / sem_t / atomic 操作 / RCU |
| 硬編碼協議 (端口字符串、固定結構) | 序列化框架:Protobuf/FlatBuffers/Cap'n Proto + **應用層協議** (長度前綴/分幀) |
| 超時用 alarm/SIGALRM | timerfd + epoll / std::chrono + 定時器堆 / gRPC deadline |