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

套接字程式設計核心原理:Client/Server 模型、基礎 API 與典型時序圖完整解析

     編輯:關於C語言

套接字是網路程式設計的核心抽象,掌握其建立、連線、資料傳輸、多工與關閉的完整生命週期,是開發高效、穩健網路應用的關鍵。本文以 TCP/IP 為基礎,系統講解 Client/Server 互動模型、七大基礎套接字 API、資料結構定義,並以三張時序圖呈現面向連線/無連線協定的呼叫流程與應用程式邏輯流向。

一、Client/Server 互動模型

TCP/IP 網路中兩個進程的互動遵循 非對稱、非同步 的 Client/Server 模式:

Server 端流程

  1. socket() 建立套接字
  2. bind() 綁定本地 IP/埠
  3. listen() 監聽,進入被動等待狀態
  4. accept() 接受連線,回傳新套接字專責該客戶
  5. 迴圈:recv() 接收請求 → 處理 → send() 回應
  6. closesocket() 關閉客戶套接字,回 accept() 等待下一個

Client 端流程

  1. socket() 建立套接字
  2. connect() 主動連線至伺服器 IP/埠
  3. 迴圈:send() 發送請求 → recv() 等待回應
  4. closesocket() 關閉連線

二、七大基礎套接字 API 詳細定義

1. socket() — 建立套接字

SOCKET socket(int af, int type, int protocol);
af: AF_INET (IPv4), AF_INET6 (IPv6)
type: SOCK_STREAM (TCP), SOCK_DGRAM (UDP)
protocol: 0 (自動選擇), IPPROTO_TCP, IPPROTO_UDP
返回: 成功套接字描述符,失敗 INVALID_SOCKET

2. bind() — 綁定本地位址

int bind(SOCKET s, const struct sockaddr* name, int namelen);
sockaddr_in 結構:
  sin_family: AF_INET
  sin_port: htons(埠號) // 網路位元組序
  sin_addr.s_addr: htonl(INADDR_ANY) // 所有介面
  sin_zero[8]: 保留歸零
返回: 0 成功,SOCKET_ERROR 失敗

3. listen() — 進入監聽狀態

int listen(SOCKET s, int backlog);
backlog: 等待佇列最大長度(建議 SOMAXCONN)
僅適用 SOCK_STREAM

4. connect() / accept() — 建立連線

// Client 主動連線
int connect(SOCKET s, const struct sockaddr* name, int namelen);

// Server 接受連線,回傳新套接字
SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen);
addr: 回填客戶端 IP/埠
addrlen: 傳入/傳出緩衝區長度

5. send() / recv() — 資料傳輸

int send(SOCKET s, const char* buf, int len, int flags);
int recv(SOCKET s, char* buf, int len, int flags);
flags: 0 一般, MSG_OOB (帶外數據), MSG_PEEK (窺視不移除)
返回: 實際傳送/接收位元組數,0 表對方關閉,SOCKET_ERROR 失敗

6. select() — 多工監視

int select(int nfds, fd_set* readfds, fd_set* writefds,
           fd_set* exceptfds, const struct timeval* timeout);
readfds: 可讀性檢測集合
writefds: 可寫性檢測集合
exceptfds: 例外狀況檢測集合
timeout: NULL 永久等待, {0,0} 非阻塞輪詢
返回: 就緒描述符總數,0 超時,SOCKET_ERROR 失敗

7. closesocket() — 關閉套接字

int closesocket(SOCKET s);
// 參考計數歸零時釋放核心資料結構
// TCP 發送 FIN,進入 TIME_WAIT

三、關鍵資料結構:sockaddr_in

struct sockaddr_in {
    short            sin_family;   // AF_INET
    u_short          sin_port;     // 16-bit 埠號,網路序
    struct in_addr   sin_addr;     // 32-bit IP,網路序
    char             sin_zero[8];  // 填零對齊
};
struct in_addr { union { u_long s_addr; } }; // IPv4 位址

四、典型時序圖

2.1 面向連線套接字系統呼叫時序

TCP 連線建立與資料傳輸時序

圖:Server listen/accept ↔ Client connect → send/recv 交替 → 雙向 close

2.2 無連線協定套接字調用時序

UDP 無連線收發時序

圖:Client sendto → Server recvfrom → Server sendto → Client recvfrom,無連線建立階段

2.3 面向連線應用程式流程圖

TCP 應用程式邏輯流程

圖:Server 主迴圈 accept → fork/thread 處理 → Client 連線收發迴圈

五、實戰關鍵點提醒

六、從同步到非同步的演進

graph LR
    Sync[同步阻塞\n單執行緒/連線一執行緒] --> Select[select 多工\n單執行緒管理多連線]
    Select --> WSAAsync[WSAAsyncSelect\n視窗訊息驅動]
    WSAAsync --> WSAEvent[WSAEventSelect\n事件物件驅動]
    WSAEvent --> IOCP[IOCP 完成埠\n高擴展性伺服器]

總結

套接字 API 雖精簡,但正確處理「部分傳輸」、「位元組序」、「非阻塞多工」、「優雅關閉」等細節,才能寫出生產級網路程式。建議先掌握同步阻塞模式的完整流程,再逐步遷移至 select、WSAEventSelect、IOCP 等進階模型。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
議題關鍵點
位元組序埠號/IP 必須 htons/htonl 轉網路序,接收後 ntohs/ntohl 轉主機序
部分傳送/接收send/recv 可能不足 len,必須迴圈處理剩餘資料
非阻塞模式ioctlsocket/FIONBIO 或 WSAEventSelect,配合 select 實現單執行緒多連線
優雅關閉shutdown(s, SD_SEND) 發送 FIN,持續 recv 至 0,再 closesocket
TIME_WAIT主動關閉方進入 2MSL 等待,SO_REUSEADDR 可讓新連線重用埠
錯誤處理WSAGetLastError() 取得錯誤碼:WSAEWOULDBLOCK、WSAECONNRESET、WSAETIMEDOUT 等