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

WinSock 程式設計學習筆記 (一):Socket 基礎、資料結構與完整通訊流程

     編輯:關於VC++

本文系統整理 Windows Socket (WinSock 2.0) 程式設計的核心基礎知識,涵蓋 Socket 類型、必要開發檔案、關鍵資料結構、協議常數、Socket 選項,以及從初始化到關閉的完整通訊流程與程式碼範例。

一、Socket 核心概念與類型

Socket 相當於網路通訊兩端的「插座」,定義為 typedef unsigned int SOCKET;。五種類型中最常用三種:

類型常數特性
流式套接字 (Stream)SOCK_STREAM (1)TCP、連線導向、可靠、有序、無邊界、適合大量資料
資料報套接字 (Datagram)SOCK_DGRAM (2)UDP、無連線、不可靠、有邊界、效率高、支援廣播
原始套接字 (Raw)SOCK_RAW (3)保留完整 IP 標頭,適用封包分析、防火牆開發

二、開發環境必要檔案 (WinSock 2.0)

  • 標頭檔:Winsock2.h
  • 匯入庫:WS2_32.LIB
  • 動態庫:WS2_32.DLL

三、關鍵資料結構

1. 基本資料型別

typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned int u_int;
typedef unsigned long u_long;

2. 網路位址結構

舊版 in_addr (聯合體):含 s_b1..s_b4、s_w1..s_w2、S_addr (常用)。

新版 in_addr:直接為 u_long S_addr。
範例:INADDR_LOOPBACK (127.0.0.1) = 0x7F000001。

3. Socket 位址結構

sockaddr:通用結構,sa_family (通常 AF_INET) + sa_data[14]。
sockaddr_in:專用於 TCP/IP (Internet 域),實務上一律使用此結構:

struct sockaddr_in {
  short sin_family;      // AF_INET
  u_short sin_port;      // 埠號 (網路序,用 htons)
  struct in_addr sin_addr; // IP 位址 (u_long)
  char sin_zero[8];      // 填充,對齊用
};

常用宏:INADDR_ANY (0) 表示綁定所有本機介面。

4. 主機資訊結構 hostent

struct hostent {
  char FAR * h_name;        // 官方主機名
  char FAR * FAR * h_aliases; // 別名列表
  short h_addrtype;         // 位址類型 (AF_INET)
  short h_length;           // 位址長度 (4)
  char FAR * FAR * h_addr_list; // IP 位址列表 (多網卡)
  #define h_addr h_addr_list[0]
};

5. 協議常數

IPPROTO_IP   0
IPPROTO_ICMP 1
IPPROTO_TCP  6
IPPROTO_UDP  17
IPPROTO_RAW  255

四、Socket 選項 (Socket Options)

透過 getsockopt/setsockopt 讀寫,層級 level 通常為 IPPROTO_IP 或 SOL_SOCKET。常用選項:

選項值說明
SO_REUSEADDR0x0004允許本地位址重用
SO_KEEPALIVE0x0008保持連線 (心跳)
SO_BROADCAST0x0020允許廣播
SO_LINGER0x0080關閉時延遲傳送未送資料
SO_SNDBUF / SO_RCVBUF0x1001/0x1002發送/接收緩衝區大小
SO_SNDTIMEO / SO_RCVTIMEO0x1005/0x1006發送/接收逾時 (毫秒)

五、完整 Socket 通訊流程與程式碼範例

1. 初始化 WinSock

WORD wVersion = MAKEWORD(2,0);
WSADATA wsData;
int nResult = WSAStartup(wVersion, &wsData);
if (nResult != 0) { /* 錯誤處理 */ }
// 成功後 wsData.wVersion=2, wHighVersion=514 (2.2)

2. 建立 Socket

SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (sock == INVALID_SOCKET) { /* 錯誤處理 */ }

3. 綁定本地位址

sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(0); // 0 = 系統自動指派
addr.sin_addr.s_addr = inet_addr("192.168.1.100");
int nResult = bind(sock, (sockaddr*)&addr, sizeof(sockaddr));

4. 伺服器端:監聽與接受連線

listen(sock, 5); // 最大等待佇列 5
sockaddr_in clientAddr;
SOCKET clientSock = accept(sock, (sockaddr*)&clientAddr, &addrLen);

5. 用戶端:連接伺服器

sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8080);
serverAddr.sin_addr.s_addr = inet_addr("192.168.1.200");
connect(sock, (sockaddr*)&serverAddr, sizeof(sockaddr));

6. 資料收發

// 發送
char buf[] = "Hello";
send(sock, buf, strlen(buf), 0);

// 接收
char recvBuf[1024];
int len = recv(sock, recvBuf, 1024, 0);

Flags 參數:0 (預設)、MSG_OOB (帶外/緊急)、MSG_PEEK (窺視不移除)、MSG_DONTROUTE (不經路由)。

7. 關閉連線與釋放資源

shutdown(sock, SD_BOTH); // SD_RECEIVE(0)/SD_SEND(1)/SD_BOTH(2)
closesocket(sock);
WSACleanup(); // 進程結束前呼叫一次

六、總結

掌握上述結構與流程,即可撰寫基本的 TCP/UDP 用戶端/伺服器程式。進階主題 (非阻塞 I/O、IOCP、SSL/TLS、IPv6) 將於後續筆記說明。

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