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

深入解析 Visual C++ Winsock API 網絡程式設計

     編輯:關於VC++

前言

在 90 年代初期,為了統一 Windows 平台下的網絡程式開發介面,Microsoft 聯合多家廠商共同制定了 Windows Sockets(Winsock)規範。Winsock 並非一種網絡協議,而是一套開放的、支援多種協議的程式設計介面。現今的 Winsock 已實現與協議無關,開發者可透過它調用 TCP/IP、UDP 等多種協議功能,其中 TCP/IP 為最常用。Socket 在電腦中提供一個通訊端口,應用程式在網絡上收發資料皆須經由此介面。

VC 中 Winsock API 開發的必要文件

使用 Visual C++ 進行 Winsock API 開發時,專案必須包含以下三個文件,否則會出現編譯錯誤:

  • WINSOCK.H:Winsock API 的標頭文件。
  • WSOCK32.LIB:Winsock API 連接庫,需將其加入專案的非預設連接庫中。
  • WINSOCK.DLL:動態連接庫,位於 Windows 安裝目錄下。

一、伺服器端 Socket 操作流程

1. 初始化 Winsock DLL

呼叫 WSAStartup() 初始化 Windows Sockets DLL,只有此函數成功後,才能調用其他 Winsock API。典型調用方式:

WSAStartup(MAKEWORD(1,1), &WSAData);

其中 MAKEWORD(1,1) 表示使用 Winsock 1.1 版本,WSAData 結構用於接收系統回傳的資訊。

2. 建立監聽 Socket

呼叫 socket() 建立 Socket 並指定通訊協議:

SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  • af:地址家族,通常為 AF_INET。
  • type:Socket 類型,SOCK_STREAM 為 TCP 流式,SOCK_DGRAM 為 UDP 資料報。
  • protocol:協議類型,TCP 為 IPPROTO_TCP。

成功返回 Socket 描述符,失敗返回 INVALID_SOCKET,可透過 WSAGetLastError() 取得錯誤代碼。

3. 綁定 IP 與埠號

使用 bind() 為 Socket 指定本機 IP 與埠號,讓客戶端知曉連接目標:

bind(s, (sockaddr*)&addr, sizeof(addr));

若不指定具體 IP,可設為 INADDR_ANY;埠號設為 0 則由系統自動分配(1024~5000)。

4. 進入監聽狀態

呼叫 listen() 建立連接請求佇列,參數 backlog 指定最大佇列長度(上限 5):

listen(s, 5);

5. 非同步事件通知與接受連接

為了讓系統主動通知客戶端連接請求,需使用 WSAAsyncSelect() 註冊網絡事件:

WSAAsyncSelect(s, hWnd, WM_USER+1, FD_ACCEPT | FD_READ | FD_CLOSE);

當客戶端發起連接,視窗會收到自訂訊息,在訊息處理函數中根據 lParam 判斷事件類型(FD_ACCEPT、FD_READ 等),並呼叫 accept() 建立新的通訊 Socket:

SOCKET client = accept(s, (sockaddr*)&clientAddr, &len);

原監聽 Socket 繼續監聽,新 Socket 用於與該客戶端通訊。

6. 關閉連接與清理資源

通訊結束時呼叫 closesocket() 關閉 Socket,程式退出前必須呼叫 WSACleanup() 釋放 Winsock 佔用的資源。

二、客戶端 Socket 操作

客戶端同樣需先呼叫 WSAStartup() 與 socket()。不同之處在於:

  • 可選擇性呼叫 bind() 指定本地 IP/埠,或由系統自動分配。
  • 呼叫 connect() 主動向伺服器發起連接:
connect(s, (sockaddr*)&serverAddr, sizeof(serverAddr));

三、資料傳送:TCP 與 UDP 的差異

特性TCP (SOCK_STREAM)UDP (SOCK_DGRAM)
連接方式面向連接無連接
可靠性可靠、有序、不重複不可靠、可能亂序、重複、丟包
發送/接收函數send() / recv()sendto() / recvfrom()

絕大多數應用為保證資料正確性,均採用 TCP。TCP 的 send() 在阻塞模式下會等待緩衝區可用;非阻塞模式則發送盡可能多的資料即返回。

四、自訂 CMySocket 類別實現

為封裝底層 API 並簡化錯誤處理,文中實作了一個 CMySocket 類別,主要成員函數如下:

  • Create():建立 TCP Socket。
  • Bind() / Listen() / Accept():伺服器端綁定、監聽、接受連接。
  • Connect():客戶端發起連接,支援主機名或 IP 解析。
  • Send() / Receive():資料收發。
  • asyncSelect():註冊非同步事件通知。
  • Close():關閉 Socket 並重置內部結構。
  • 建構函數自動呼叫 WSAStartup(),解構函數自動呼叫 WSACleanup()。

使用時,伺服器端需建立兩個 CMySocket 物件(一個監聽、一個通訊),客戶端建立一個即可。若需支援多連接,可增加物件,但注意單進程監聽佇列上限為 5。

總結

本文系統闡述了 Winsock API 的核心流程與關鍵函數,並提供了可復用的 CMySocket 類別原始碼。開發者可在此基礎上擴充更多功能(如獲取遠端 IP、主機名等),快速構建穩健的網絡應用程式。

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