本文解析一個 MFC 單文件介面 (SDI) 應用程式,實現 UDP 伺服器端監聽、資料接收、顯示與回傳的完整流程。涉及 Winsock 初始化、Socket 建立/繫結、背景執行緒監聽、訊息泵整合、UI 更新同步等關鍵技術。
// 通訊相關
SOCKET m_sock; // UDP Socket
HANDLE m_hListenThread; // 監聽執行緒句柄
BOOL m_bInitialized; // Winsock 初始化旗標
WSADATA WSAData; // Winsock 資料結構
BOOL flag; // 通用旗標
SOCKADDR_IN saClnt; // 客戶端位址
int saClntLen; // 位址結構長度
BOOL Isconnect; // 連線狀態 (UDP 無連線,此處語意為「已就緒」)
// UI 相關
CSize sizeTotal; // 捲軸範圍
int count; // 訊息計數
CString m_data[1000]; // 訊息緩衝陣列 (固定大小,生產環境建議用 CList/CArray)
char Hostname[260]; // 主機名
char Hostaddress[20]; // 主機 IP
WSAStartup(0x0101, &wsaData) 要求 1.1 版本socket(AF_INET, SOCK_DGRAM, 0) 資料報模式bind(m_sock, (sockaddr*)&sa, sizeof(sa)) 綁定 INADDR_ANY:5050CreateThread(NULL, 0, Listen, this, 0, &idThread)錯誤處理:每步驟失敗時記錄 m_data 並清理已分配資源。
DWORD WINAPI Listen(LPVOID lpParam) {
CServerView* pView = (CServerView*)lpParam;
char buffer[1024];
int nLen = sizeof(pView->saClnt);
while (pView->Isconnect) {
int nRecv = recvfrom(pView->m_sock, buffer, sizeof(buffer), 0,
(sockaddr*)&pView->saClnt, &nLen);
if (nRecv > 0) {
buffer[nRecv] = '\0';
CString msg = "Received: " + CString(buffer);
// 執行緒安全更新 UI:PostMessage 而非直接呼叫
pView->PostMessage(WM_USER_RECEIVED, 0, (LPARAM)new CString(msg));
// 回傳 Echo
sendto(pView->m_sock, buffer, nRecv, 0,
(sockaddr*)&pView->saClnt, nLen);
}
}
return 0;
}
關鍵點:
recvfrom 同時取得資料與發送者位址PostMessage 送自定義訊息 (WM_USER_RECEIVED) 至主執行緒CString* 傳遞訊息內容,接收端負責 delete// 訊息映射
ON_MESSAGE(WM_USER_RECEIVED, OnReceived)
// 處理函數
LRESULT CServerView::OnReceived(WPARAM, LPARAM lParam) {
CString* pMsg = (CString*)lParam;
m_data[count++] = *pMsg;
delete pMsg;
// 更新 ListBox/滾動顯示...
return 0;
}
Isconnect = FALSE; // 通知執行緒退出
if (m_hListenThread) {
WaitForSingleObject(m_hListenThread, 2000); // 等待執行緒結束
CloseHandle(m_hListenThread);
}
if (m_sock != INVALID_SOCKET) closesocket(m_sock);
if (m_bInitialized) WSACleanup();
m_data[1000] 易溢位,改用 CList<CString> 或循環緩衝區WSAGetLastError() 區分 WSAEWOULDBLOCK (非阻塞無資料) 與真正錯誤sockaddr_storage、getaddrinfo 替代硬編碼 IPv4 結構socket(AF_INET, SOCK_DGRAM, 0) 建立 Socketsendto 直接發送至伺服器 IP:Portrecvfrom 接收回傳資料bind 固定本地埠口 (穿透 NAT 需固定埠)此架構展示 MFC 視窗應用整合 Winsock 非阻塞通訊的標準範式,可延伸至 TCP、SSL/TLS、自定義協定等場景。