不同於 UDP 的「發後即忘」,TCP(Transmission Control Protocol,傳輸控制協議)提供面向連接、可靠、有序、雙向字節流服務。WinSock 透過 SOCK_STREAM 類型支援 TCP,MFC CSocket 進一步封裝了「監聽-接受-通信」的經典流程。
TCP 通信必須有一方扮演伺服器(Server),另一方為客戶端(Client):
Create → Bind → Listen → Accept(產生新 Socket 專責通信)Create → Connect(主動發起連線)Send/Receive 雙向收發,順序嚴格保證。| 階段 | Server 端 | Client 端 |
|---|---|---|
| 建立 Socket | Create(6802, SOCK_STREAM) | Create(0, SOCK_STREAM) |
| 綁定地址 | Bind(6802, "127.0.0.1") | 通常不需綁定(系統自動分配) |
| 監聽/連線 | Listen(5) → Accept(newSock) | Connect("127.0.0.1", 6802) |
| 資料收發 | newSock.Send/Receive | sock.Send/Receive |
BOOL CMy63_s1_serverDlg::OnInitDialog() {
CDialog::OnInitDialog();
CSocket sockListen;
// 1. 建立監聽 Socket
sockListen.Create(6802, SOCK_STREAM, "127.0.0.1");
sockListen.Bind(6802, "127.0.0.1");
sockListen.Listen(5); // 佇列長度 5
// 2. 等待客戶端連線(阻塞直到連線到來)
sockListen.Accept(m_sockSend); // m_sockSend 為成員變量,用於後續通信
// 3. 關閉監聽 Socket(單連線範例),釋放資源
sockListen.Close();
// 4. 啟動定時器,模擬主動推送數據
SetTimer(1, 3000, NULL);
return TRUE;
}
void CMy63_s1_serverDlg::OnTimer(UINT nIDEvent) {
static int i = 0;
char buf[32];
sprintf_s(buf, "Server Msg %04d", i++);
m_sockSend.Send(buf, strlen(buf)); // 直接 Send,無需指定地址
}
BOOL CMy63_s1_clientDlg::OnInitDialog() {
CDialog::OnInitDialog();
m_sockClient.Create(0, SOCK_STREAM, NULL); // 埠號 0 由系統分配
// 連線到伺服器
if (!m_sockClient.Connect("127.0.0.1", 6802)) {
AfxMessageBox("連線失敗!");
return FALSE;
}
return TRUE;
}
void CMy63_s1_clientDlg::OnReceive(int nErrorCode) {
char buf[1024];
int nLen = m_sockClient.Receive(buf, sizeof(buf) - 1);
if (nLen > 0) {
buf[nLen] = '\0';
// 更新 UI 顯示收到的數據
}
CAsyncSocket::OnReceive(nErrorCode);
}
Accept/Connect/Receive 會暫停執行緒,適合簡單教學或獨立執行緒。Create(..., FD_READ | FD_ACCEPT | FD_CONNECT | FD_CLOSE) 並處理 WM_SOCKET_NOTIFY 訊息,避免界面凍結。Accept 產生新 Socket,建議放入 CList 或使用 CAsyncSocket 派生類管理多連線。ShutDown(SD_SEND) → 接收方收到 OnReceive(0) → 雙方 Close(),避免數據丟失。| 現象 | 原因 | 對策 |
|---|---|---|
| Connect 立即失敗 WSAECONNREFUSED | Server 未 Listen 或埠號錯誤 | 確認 Server 先啟動、IP/埠匹配、防火牆放行 |
| Send 返回 SOCKET_ERROR | 連線已斷開或緩衝區滿 | 檢查 GetLastError(),配合 OnSend 事件流控 |
| Receive 收到空數據 (0 字節) | 對方關閉連線 (FIN) | 視為連線結束,執行清理邏輯 |
| 粘包/拆包 | TCP 是無邊界字節流 | 應用層定義協議頭(長度/分隔符)自行拆包 |
TCP 通信的核心在於「連線建立的三次握手」與「可靠字節流」。MFC CSocket 將底層 socket/bind/listen/accept/connect 封裝為直觀的成員函數,讓開發者專注於業務邏輯。理解「監聽 Socket 與通信 Socket 分離」、「阻塞與異步模式選擇」、「應用層協議設計」三大關鍵,即可構建健壯的網路應用。