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

Windows 網絡編程實戰:TCP/UDP Socket 完整開發指南

     編輯:關於C語言

核心區別

特性TCP (SOCK_STREAM)UDP (SOCK_DGRAM)
連接模式面向連接,三次握手無連接,數據報
可靠性可靠、有序、無重複不可靠、無序、可能重複/丟失
流控/擁塞控制有無
典型場景檔案傳輸、Web、郵件、SSH即時通訊、視訊串流、DNS、遊戲

Winsock 初始化(雙方通用)

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")

TCP 服務端完整流程

// 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();

TCP 客戶端完整流程

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();

UDP 服務端(無連接,單向/雙向均用 sendto/recvfrom)

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();

UDP 客戶端

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();

關鍵 API 速查

  • htonl/htons:主機序 → 網絡序(大端)
  • inet_addr:點分十進制 → in_addr
  • inet_ntoa:in_addr → 字串(非線程安全,建議 InetNtop)
  • WSAGetLastError():獲取錯誤碼

運行效果

TCP 通訊示例輸出 UDP 通訊示例輸出

進階提示

  1. 錯誤處理:每個 socket API 都要檢查返回值,SOCKET_ERROR 時調用 WSAGetLastError。
  2. 非阻塞/異步:ioctlsocket(FIONBIO)、WSAAsyncSelect、WSAEventSelect、IOCP。
  3. 優雅關閉:TCP 需 shutdown(sock, SD_SEND) → recv 讀到 0 → closesocket。
  4. IPv6 相容:使用 getaddrinfo、sockaddr_storage 雙棧編程。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved