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

MFC UDP Socket 實作伺服器與客戶端雙向通訊完整範例

     編輯:關於C++

前言:MFC 非同步 UDP 通訊架構

本文提供一套基於 MFC (Microsoft Foundation Classes) 的 UDP 伺服器/客戶端雙向通訊完整實作。採用 CAsyncSocket 衍生類別搭配執行緒監聽,實現無連線、低延遲的訊息收發,適合即時訊息、廣播、遊戲狀態同步等場景。

專案結構

  • Server 專案:單一檢視 SDI 應用,含監聽執行緒、訊息顯示區、本機 IP 顯示、發送訊息對話框
  • Client 專案:單一檢視 SDI 應用,含撥號連線對話框、監聽執行緒、訊息收發介面

核心類別與變數設計 (ServerView.h)

class CServerView : public CView {
    // 通訊相關
    SOCKET m_sock;                    // UDP Socket
    HANDLE m_hListenThread;           // 監聽執行緒
    BOOL m_bInitialized;              // Winsock 初始化旗標
    SOCKADDR_IN saClnt; int saClntLen; // 客戶端位址
    BOOL Isconnect;                   // 連線狀態

    // 訊息緩衝
    CString m_data[1000];
    int count;
    CSize sizeTotal;
    BOOL flag;

    // 執行緒函數
    static UINT WINAPI Listen(LPVOID pParam);
};

關鍵流程實作

1. 建構函數:初始化 Winsock、建立 Socket、綁定 Port 5050、啟動監聽執行緒

CServerView::CServerView() {
    WSADATA wsaData;
    WSAStartup(0x0101, &wsaData); // 版本 1.1
    m_sock = socket(AF_INET, SOCK_DGRAM, 0);

    sockaddr_in sa = {AF_INET, htons(5050), INADDR_ANY};
    bind(m_sock, (SOCKADDR*)&sa, sizeof(sa));

    m_hListenThread = CreateThread(NULL, 0, Listen, this, 0, &idThread);
}

2. 監聽執行緒:處理附著/離脫/訊息三類協定

UINT WINAPI CServerView::Listen(LPVOID pParam) {
    CServerView* pView = (CServerView*)pParam;
    char msg[2000]; SOCKADDR_IN saClnt; int saClntLen;

    while (1) {
        saClntLen = sizeof(saClnt);
        int n = recvfrom(pView->m_sock, msg, 1024, 0, (SOCKADDR*)&saClnt, &saClntLen);
        if (n < 0) continue;

        switch (msg[0]) {
            case 'A': // 客戶端附著
                wsprintf(msg, "A: Client from %s attached\n", inet_ntoa(saClnt.sin_addr));
                pView->Isconnect = TRUE; pView->saClnt = saClnt; pView->saClntLen = saClntLen;
                sendto(pView->m_sock, msg, 1024, 0, (SOCKADDR*)&saClnt, saClntLen);
                break;
            case 'D': // 客戶端離脫
                wsprintf(msg, "D: Client from %s detached\n", inet_ntoa(saClnt.sin_addr));
                pView->Isconnect = FALSE;
                sendto(pView->m_sock, msg, 1024, 0, (SOCKADDR*)&saClnt, saClntLen);
                break;
            case 'R': // 一般訊息
                pView->m_data[pView->count++] = msg;
                pView->flag = TRUE; pView->InvalidateRect(NULL);
                break;
        }
    }
    return 0;
}

3. 客戶端撥號連線 (ClientView::OnDial)

  • 輸入 Server IP,建立 UDP Socket 綁定隨機 Port
  • 啟動監聽執行緒,發送 'A' 附著封包
  • 執行緒持續 recvfrom 接收回應與訊息

4. 訊息發送 (雙向)

// Server 發送給 Client
wsprintf(msg, "R: %s", userInput);
sendto(m_sock, msg, 1024, 0, (SOCKADDR*)&saClnt, saClntLen);

// Client 發送給 Server (同樣格式)
sendto(m_sock, msg, 1024, 0, (SOCKADDR*)&m_saSrvr, sizeof(m_saSrvr));

編譯與執行要點

  • 專案 Link 設定加入 wsock32.lib
  • 編譯產生 Server.exe、Client.exe
  • 同一區域網路下雙機執行,Client 輸入 Server IP 即可通訊
  • 通訊協定簡單:'A' 附著、'D' 離脫、'R' 訊息

改進建議

  • 使用 CAsyncSocket 封裝替代原生 Socket,簡化非同步通知
  • 加入封包序號、重傳機制提升可靠度 (UDP 本質不可靠)
  • 訊息緩衝區改用 CList<CString> 避免陣列溢位
  • 執行緒結束改用事件旗標而非 TerminateThread
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved