單文檔介面 (SDI),伺服器監聽 UDP 埠 5050,客戶端發送訊息,雙方在視圖類別顯示收發記錄。使用 CAsyncSocket 或原始 Winsock API + 執行緒。
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。connect 僅固定 sendto 目標,recvfrom 仍可收任意來源封包。CAsyncSocket 或 CSocket 簡化非同步處理。