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

VC++ 網路程式設計總結(一):Socket 基礎與 Client/Server 實作

     編輯:關於C語言

1. Socket 程式設計核心原理

網路通訊雙方需協同工作,使用相同傳輸協定(TCP 或 UDP)。一個完整連線由五元組唯一標識:

  • 協定
  • 本地 IP 位址
  • 本地埠號
  • 遠端 IP 位址
  • 遠端埠號

2. Client/Server 通訊模型

  • Server:綁定知名埠,listen 進入被動等待,accept 接受連線,處理請求後回應。
  • Client:主動 connect 到 Server IP:Port,發送請求,接收回應。
  • 基於連線(TCP)是標準模式;無連線(UDP)適用簡單查詢/廣播。

3. Winsock 程式設計關鍵步驟

  1. WSAStartup:載入 Winsock DLL,協商版本(通常 MAKEWORD(2,2))。
  2. 建立 Socket:socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)。
  3. 填寫 sockaddr_in:sin_family=AF_INET、sin_port=htons(port)、sin_addr.s_addr=inet_addr(ip)。
  4. Client:connect;Server:bind → listen → accept。
  5. 資料收發:send/recv(TCP);sendto/recvfrom(UDP)。
  6. 關閉:closesocket → WSACleanup。

4. 完整範例:TCP Echo Server / Client

Server 端

// Server.cpp
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")

int main() {
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) return 1;

    SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (s == INVALID_SOCKET) return 1;

    SOCKADDR_IN addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8888);
    addr.sin_addr.s_addr = htonl(INADDR_ANY); // 監聽所有介面

    if (bind(s, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR) return 1;
    if (listen(s, SOMAXCONN) == SOCKET_ERROR) return 1;

    printf("Server listening on port 8888...\n");

    while (1) {
        SOCKADDR_IN clientAddr;
        int addrLen = sizeof(clientAddr);
        SOCKET client = accept(s, (SOCKADDR*)&clientAddr, &addrLen);
        if (client == INVALID_SOCKET) continue;

        printf("Client connected: %s:%d\n",
               inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));

        char buf[1024];
        int recvLen;
        while ((recvLen = recv(client, buf, sizeof(buf)-1, 0)) > 0) {
            buf[recvLen] = '\0';
            printf("Received: %s\n", buf);
            send(client, buf, recvLen, 0); // Echo back
        }

        closesocket(client);
    }

    closesocket(s);
    WSACleanup();
    return 0;
}

Client 端

// Client.cpp
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")

int main() {
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2,2), &wsaData);

    SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    SOCKADDR_IN addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8888);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    if (connect(s, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR) {
        printf("Connect failed: %d\n", WSAGetLastError());
        return 1;
    }

    const char *msg = "Hello from Client!";
    send(s, msg, (int)strlen(msg), 0);

    char buf[1024];
    int len = recv(s, buf, sizeof(buf)-1, 0);
    if (len > 0) {
        buf[len] = '\0';
        printf("Server echo: %s\n", buf);
    }

    closesocket(s);
    WSACleanup();
    return 0;
}

5. 執行結果示意

Server 執行畫面 Client 執行畫面

6. 關鍵注意事項

  • 位元組序:埠號、IP 位址必須用 htons/htonl 轉網路序(Big Endian)。
  • 錯誤處理:每個 Socket API 皆需檢查回傳值,失敗呼叫 WSAGetLastError()。
  • 阻塞 vs 非阻塞:預設阻塞;高併發需用 ioctlsocket(FIONBIO) 或 select/WSAEventSelect/IOCP。
  • 資料邊界:TCP 為串流,無訊息邊界;應用層需自行定義協議(長度前綴、分隔符等)。
  • 優雅關閉:shutdown(s, SD_SEND) 發送 FIN,對端 recv 返回 0,再 closesocket。

7. 後續主題預告

  • 非阻塞 I/O 與 select/WSAAsyncSelect/IOCP 模型比較。
  • UDP 程式設計與廣播/多點傳送。
  • SSL/TLS 加密通訊(Schannel / OpenSSL)。
  • 網路程式除錯工具:Wireshark、Netmon、TCPView。

Socket 程式設計基石在於理解 TCP 狀態機與 Winsock API 契約。熟練掌握同步阻塞模型後,再進階至高效能非阻塞架構,才能構建穩定、可擴展的網路應用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved