使用 C++ 原生 Socket API 實現簡單 TCP 服務端與客戶端:服務端啟動監聽線程循環 accept,收到請求回應後繼續監聽;客戶端連接、發送、接收、關閉完整流程。
DWORD WINAPI ListenThread(LPVOID param)
{
CServerDlg* dlg = (CServerDlg*)param;
if (listen(dlg->m_Listening, 40) == SOCKET_ERROR) return 0;
char buf[MAX_PATH];
while (true)
{
SOCKET client = accept(dlg->m_Listening, (sockaddr*)&cliAddr, &len);
char* ip = inet_ntoa(cliAddr.sin_addr);
dlg->Receive(client, buf, 100);
dlg->SetRequestText(buf);
strcat(buf, " :我是老貓,收到(");
strcat(buf, ip);
strcat(buf, ")");
dlg->Send(client, buf, 100);
}
return 0;
}
int Receive(SOCKET fd, char* buf, int len)
{
int cnt = len, rc;
while (cnt > 0)
{
rc = recv(fd, buf, cnt, 0);
if (rc == SOCKET_ERROR) return -1;
if (rc == 0) return len - cnt;
buf += rc; cnt -= rc;
}
return len;
}
int Send(SOCKET fd, char* buf, int len)
{
int cnt = len, rc;
while (cnt > 0)
{
rc = send(fd, buf, cnt, 0);
if (rc == SOCKET_ERROR) return -1;
if (rc == 0) return len - cnt;
buf += rc; cnt -= rc;
}
return len;
}
void CClientDlg::OnSend()
{
// 解析 IP、端口、構造 sockaddr_in
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s, (sockaddr*)&local, sizeof(local)) < 0) { ... }
Send(s, requestBuf, 100);
memset(replyBuf, 0, MAX_PATH);
Receive(s, replyBuf, 100);
// 顯示回應
closesocket(s);
}
INADDR_ANY 自動獲取本機 IP,端口 2000。CreateThread 啟動監聽線程,主線程保持 UI 響應。127.0.0.1,局域網測試時客戶端填寫服務端真實 IP。send/recv 可能發送/接收不完全,必須循環調用直到完成或出錯。