首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

WinSock 有連接通信深度解析:TCP 協議與 CSocket 客戶端/伺服器模型

     編輯:關於C語言

TCP 與 UDP 的本質差異

不同於 UDP 的「發後即忘」,TCP(Transmission Control Protocol,傳輸控制協議)提供面向連接、可靠、有序、雙向字節流服務。WinSock 透過 SOCK_STREAM 類型支援 TCP,MFC CSocket 進一步封裝了「監聽-接受-通信」的經典流程。

通信角色與流程圖解

TCP 通信必須有一方扮演伺服器(Server),另一方為客戶端(Client):

  1. Server:Create → Bind → Listen → Accept(產生新 Socket 專責通信)
  2. Client:Create → Connect(主動發起連線)
  3. 連線建立後,雙方均可用 Send/Receive 雙向收發,順序嚴格保證。

關鍵 API 對照表

階段Server 端Client 端
建立 SocketCreate(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/Receivesock.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 會暫停執行緒,適合簡單教學或獨立執行緒。
  • 異步模式(推薦 GUI 應用):Create(..., FD_READ | FD_ACCEPT | FD_CONNECT | FD_CLOSE) 並處理 WM_SOCKET_NOTIFY 訊息,避免界面凍結。
  • 多客戶端併發:Server 每次 Accept 產生新 Socket,建議放入 CList 或使用 CAsyncSocket 派生類管理多連線。
  • 優雅關閉:發送方 ShutDown(SD_SEND) → 接收方收到 OnReceive(0) → 雙方 Close(),避免數據丟失。

常見坑與解決方案

現象原因對策
Connect 立即失敗 WSAECONNREFUSEDServer 未 Listen 或埠號錯誤確認 Server 先啟動、IP/埠匹配、防火牆放行
Send 返回 SOCKET_ERROR連線已斷開或緩衝區滿檢查 GetLastError(),配合 OnSend 事件流控
Receive 收到空數據 (0 字節)對方關閉連線 (FIN)視為連線結束,執行清理邏輯
粘包/拆包TCP 是無邊界字節流應用層定義協議頭(長度/分隔符)自行拆包

總結

TCP 通信的核心在於「連線建立的三次握手」與「可靠字節流」。MFC CSocket 將底層 socket/bind/listen/accept/connect 封裝為直觀的成員函數,讓開發者專注於業務邏輯。理解「監聽 Socket 與通信 Socket 分離」、「阻塞與異步模式選擇」、「應用層協議設計」三大關鍵,即可構建健壯的網路應用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved