流式套接字是 Windows Sockets 兩大核心類型之一,基於 TCP 協議提供可靠、有序、全雙工的字節流服務。本文深入剖析其核心特性、連接模型、數據打包機制、MFC 封裝優勢及經典應用場景,並對比數據報模型說明設計選型理由。
send 的數據在接收端可能合併為一次 recv,或一次 send 被拆分為多次 recv。應用層需自行定義消息邊界(長度前綴、分隔符、固定長度等)。連接建立後,雙方可同時發送和接收數據,互不干擾,如雙向車道。
socket → bind → listen → accept(阻塞等待)socket → connect(發起連接)網絡傳輸層會將字節流分段為適當大小的 TCP 段(受 MSS 限制)。CSocket 類自動處理打包與解包,應用層無需關心分段細節,直接操作字節流。
流式套接字極像電話通話:
connect/accept)closesocket)這使其成為文件傳輸協議(FTP)等大數據可靠傳輸場景的理想選擇。
| 決策因素 | 選擇流式套接字 | 選擇數據報套接字 |
|---|---|---|
| 數據可靠性要求 | 必須 100% 可靠 | 可容忍少量丟包 |
| 數據量大小 | 大數據流(文件、視頻流) | 小消息(命令、狀態、心跳) |
| 連接持久性 | 長連接會話 | 短連接/無連接 |
| 實時性要求 | 次要 | 核心(語音、遊戲) |
| 廣播/多播需求 | 不需要 | 需要 |
MFC 經典示例 CHATTER(客戶端)與 CHATSRVR(服務器)均採用流式套接字,放棄了數據報廣播模型,主要原因:
CArchive 實現 Unicode/ANSI 應用間透明通信強制要求:使用
CSocket類時 必須使用流式套接字。若在Create中指定SOCK_DGRAM,MFC 斷言失敗,程序終止。
原因:CSocket 內建的 CArchive 序列化機制要求可靠、有序的字節流,與數據報不可靠特性根本衝突。
// 方案一:長度前綴(推薦)
struct MsgHeader { uint32_t length; uint16_t type; };
// 發送:先發 Header,再發 Body
// 接收:先收 Header 解析長度,再循環收 Body 直到長度滿足
// 方案二:分隔符(適用文本協議)
// 發送:str + "\r\n"
// 接收:緩衝區查找 "\r\n" 截取完整行
// 方案三:固定長度(簡單場景)
// 固定 1024 字節/消息
// 小包高頻場景(如遊戲移動同步、鍵盤輸入)禁用 Nagle
int optval = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&optval, sizeof(optval));
// 減少 40ms 等待延遲,但增加網絡開銷
// 啟用 TCP 保活(需系統支持)
int optval = 1;
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&optval, sizeof(optval));
// 更精確控制:Windows SIO_KEEPALIVE_VALS (WSAIoctl)
// 1. 關閉發送方向,發送 FIN
shutdown(sock, SD_SEND);
// 2. 繼續接收直到對端也關閉(recv 返回 0)
char buf[1024];
while (recv(sock, buf, sizeof(buf), 0) > 0) { /* 丟棄或處理 */ }
// 3. 完全關閉
closesocket(sock);
流式套接字憑藉 TCP 的可靠性、有序性、流控制,成為大數據量、高可靠性網絡應用的基石。MFC CSocket 通過阻塞模式簡化、CArchive 序列化支持、Unicode 透明傳輸,極大降低了開發門檻。掌握字節流語義、消息邊界設計、Nagle 控制、保活檢測、優雅關閉等進階技巧,能構建健壯高效的網絡通信系統。