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

VC++ 6.0 UDP 客戶端/伺服器訊息收發程式實作

     編輯:VC 教學

架構概覽

單文檔介面 (SDI),伺服器監聽 UDP 埠 5050,客戶端發送訊息,雙方在視圖類別顯示收發記錄。使用 CAsyncSocket 或原始 Winsock API + 執行緒。

伺服器端關鍵代碼 (View 類別)

成員變數

SOCKET m_sock;           // Socket 句柄
HANDLE m_hListenThread;  // 監聽執行緒
BOOL m_bInitialized;     // Winsock 初始化旗標
CString m_msgs[1000];    // 訊息緩衝
int m_count;             // 訊息計數
CSize m_scrollSize;      // 捲軸範圍

建構函數:初始化與綁定

CServerView::CServerView() {
    m_count = 0; m_scrollSize = CSize(300, 350);
    WSADATA wsa; m_bInitialized = (WSAStartup(MAKEWORD(1,1), &wsa) == 0);
    
    m_sock = socket(AF_INET, SOCK_DGRAM, 0); // UDP
    sockaddr_in sa = {0};
    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = htonl(INADDR_ANY);
    sa.sin_port = htons(5050);
    bind(m_sock, (sockaddr*)&sa, sizeof(sa));
    
    m_hListenThread = CreateThread(NULL, 0, ListenThread, this, 0, NULL);
}

DWORD WINAPI ListenThread(LPVOID pParam) {
    CServerView* pView = (CServerView*)pParam;
    char buf[1024]; sockaddr_in cli; int clen = sizeof(cli);
    while (1) {
        int n = recvfrom(pView->m_sock, buf, 1024, 0, (sockaddr*)&cli, &clen);
        if (n > 0) {
            buf[n] = 0;
            CString msg; msg.Format(_T("Client %s: %s"), inet_ntoa(cli.sin_addr), buf);
            pView->AddMsg(msg); // 執行緒安全需 PostMessage 更新 UI
        }
    }
    return 0;
}

視圖更新與繪製

void CServerView::AddMsg(LPCTSTR psz) {
    if (m_count < 1000) m_msgs[m_count++] = psz;
    m_scrollSize.cy += 20;
    SetScrollSizes(MM_TEXT, m_scrollSize);
    Invalidate(); // 觸發 OnDraw
}

void CServerView::OnDraw(CDC* pDC) {
    for (int i = 0; i < m_count; ++i)
        pDC->TextOut(10, 10 + i * 20, m_msgs[i]);
}

客戶端端關鍵代碼

// 連接按鈕
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in sa = {0};
sa.sin_family = AF_INET;
sa.sin_port = htons(5050);
sa.sin_addr.s_addr = inet_addr(_T("127.0.0.1")); // 伺服器 IP
connect(s, (sockaddr*)&sa, sizeof(sa)); // UDP connect 只設定預設目標

// 發送按鈕
CString str; GetDlgItemText(IDC_EDIT_MSG, str);
send(s, (LPCSTR)str, str.GetLength(), 0);

資源釋放

CServerView::~CServerView() {
    if (m_bInitialized) WSACleanup();
    closesocket(m_sock);
    if (m_hListenThread) TerminateThread(m_hListenThread, 0); // 簡易結束
}

重要補充

  • 原文使用 recvfrom 迴圈於獨立執行緒,**直接操作 UI 成員變數** 非執行緒安全。正確做法:執行緒收到資料後 PostMessage(WM_USER_NEW_MSG, (WPARAM)new CString(msg)),主執行緒處理器更新陣列並 Invalidate。
  • UDP 無連線,connect 僅固定 sendto 目標,recvfrom 仍可收任意來源封包。
  • 生產環境建議改用 CAsyncSocket 或 CSocket 簡化非同步處理。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved