| 特性 | TCP (SOCK_STREAM) | UDP (SOCK_DGRAM) |
|---|---|---|
| 連接模式 | 面向連接,三次握手 | 無連接,數據報 |
| 可靠性 | 可靠、有序、無重複 | 不可靠、無序、可能重複/丟失 |
| 流控/擁塞控制 | 有 | 無 |
| 典型場景 | 檔案傳輸、Web、郵件、SSH | 即時通訊、視訊串流、DNS、遊戲 |
WORD wVersion = MAKEWORD(2, 2); // 建議 2.2
WSADATA wsaData;
if (WSAStartup(wVersion, &wsaData) != 0) return;
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
WSACleanup(); return;
}
// 記得連結 ws2_32.lib
#pragma comment(lib, "ws2_32.lib")
// 1. 建立 socket
SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);
// 2. 綁定地址/端口
SOCKADDR_IN addrSrv = {};
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 監聽所有網卡
bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(addrSrv));
// 3. 監聽
listen(sockSrv, 5); // 佇列長度 5
// 4. 迴圈接受客戶端
SOCKADDR_IN addrClient;
int len = sizeof(addrClient);
while (true) {
SOCKET sockCon = accept(sockSrv, (SOCKADDR*)&addrClient, &len);
// 5. 收發數據
char sendBuf[100];
sprintf(sendBuf, "Welcome %s", inet_ntoa(addrClient.sin_addr));
send(sockCon, sendBuf, strlen(sendBuf)+1, 0);
char recvBuf[100];
recv(sockCon, recvBuf, sizeof(recvBuf), 0);
printf("Client: %s\n", recvBuf);
closesocket(sockCon); // 關閉本次連接 socket
}
// 7. 關閉監聽 socket(通常不執行到這)
closesocket(sockSrv);
WSACleanup();
SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN addrSrv = {};
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 服務端 IP
connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(addrSrv));
// 雙向通訊
char recvBuf[100];
recv(sockClient, recvBuf, sizeof(recvBuf), 0);
printf("Server: %s\n", recvBuf);
send(sockClient, "Hello from Client", strlen("Hello from Client")+1, 0);
closesocket(sockClient);
WSACleanup();
SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0);
SOCKADDR_IN addrSrv = {};
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(addrSrv));
SOCKADDR_IN addrClient;
int len = sizeof(addrClient);
char recvBuf[100];
recvfrom(sockSrv, recvBuf, sizeof(recvBuf), 0, (SOCKADDR*)&addrClient, &len);
printf("Received: %s\n", recvBuf);
char sendBuf[100];
sprintf(sendBuf, "UDP Server replies to %s", inet_ntoa(addrClient.sin_addr));
sendto(sockSrv, sendBuf, strlen(sendBuf)+1, 0, (SOCKADDR*)&addrClient, len);
closesocket(sockSrv);
WSACleanup();
SOCKET sockClient = socket(AF_INET, SOCK_DGRAM, 0);
SOCKADDR_IN addrSrv = {};
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
sendto(sockClient, "Hello UDP Server", strlen("Hello UDP Server")+1, 0,
(SOCKADDR*)&addrSrv, sizeof(addrSrv));
char recvBuf[100];
int len = sizeof(addrSrv);
recvfrom(sockClient, recvBuf, sizeof(recvBuf), 0, (SOCKADDR*)&addrSrv, &len);
printf("Server: %s\n", recvBuf);
closesocket(sockClient);
WSACleanup();
htonl/htons:主機序 → 網絡序(大端)inet_addr:點分十進制 → in_addrinet_ntoa:in_addr → 字串(非線程安全,建議 InetNtop)WSAGetLastError():獲取錯誤碼

SOCKET_ERROR 時調用 WSAGetLastError。ioctlsocket(FIONBIO)、WSAAsyncSelect、WSAEventSelect、IOCP。shutdown(sock, SD_SEND) → recv 讀到 0 → closesocket。getaddrinfo、sockaddr_storage 雙棧編程。