亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

使用Windows Sockets 1.1編程

系統 2283 0

使用 Windows Sockets 1.1 編程

Windows Sockets 協議棧安裝檢查
任何一個與 Windows Sockets Import Library 聯接的應用程序只需簡單地調用 WSAStartup() 函數便可檢測系統中有沒有一個或多個 Windows Sockets 實現。而對于一個稍微聰明一些的應用程序來說,它會檢查 PATH 環境變量來尋找有沒有 Windows Sockets 實現的實例( Windows Sockets.DLL )。對于每一個實例,應用程序可以發出一個 LoadLibrary() 調用并且用 WSAStartup() 函數來得到這個實現的具體數據。
這一版本的 Windows Sockets 規范并沒有試圖明確地討論多個并發的 Windows Sockets 實現共同工作的情況。但這個規范中沒有任何規定可以被解釋成是限制多個 Windows Sockets DLL 同時存在并且被一個或者多個應用程序同時調用的。
套接口
(1) 基本概念
通訊的基石是套接口,一個套接口是通訊的一端。在這一端上你可以找到與其對應的一個名字。一個正在被使用的套接口都有它的類型和與其相關的進程。套接口存在于通訊域中。通訊域是為了處理一般的線程通過套接口通訊而引進的一種抽象概念。套接口通常和同一個域中的套接口交換數據(數據交換也可能穿越域的界限,但這時一定要執行某種解釋程序)。 Windows Sockets 規范支持單一的通訊域,即 Internet 域。各種進程使用這個域互相之間用 Internet 協議族來進行通訊( Windows Sockets 1.1 以上的版本支持其他的域,例如 Windows Sockets 2 )。
套接口可以根據通訊性質分類;這種性質對于用戶是可見的。應用程序一般僅在同一類的套接口間通訊。不過只要底層的通訊協議允許,不同類型的套接口間也照樣可以通訊。
用戶目前可以使用兩種套接口,即流套接口和數據報套接口。流套接口提供了雙向的,有序的,無重復并且無記錄邊界的數據流服務。數據報套接口支持雙向的數據流,但并不保證是可靠,有序,無重復的。也就是說,一個從數據報套接口接收信息的進程有可能發現信息重復了,或者和發出時的順序不同。數據報套接口的一個重要特點是它保留了記錄邊界。對于這一特點,數據報套接口采用了與現在許多包交換網絡(例如以太網)非常類似的模型。
(2)客戶機 / 服務器模型
一個在建立分布式應用時最常用的范例便是客戶機 / 服務器模型。在這種方案中客戶應用程序向服務器程序請求服務。這種方式隱含了在建立客戶機 / 服務器間通訊時的非對稱性。客戶機 / 服務器模型工作時要求有一套為客戶機和服務器所共識的慣例來保證服務能夠被提供(或被接受)。這一套慣例包含了一套協議。它必須在通訊的兩頭都被實現。根據不同的實際情況,協議可能是對稱的或是非對稱的。在對稱的協議中,每一方都有可能扮演主從角色;在非對稱協議中,一方被不可改變地認為是主機,而另一方則是從機。一個對稱協議的例子是 Internet 中用于終端仿真的 TELNET 。而非對稱協議的例子是 Internet 中的 FTP 。無論具體的協議是對稱的或是非對稱的,當服務被提供時必然存在“客戶進程”和“服務進程”。
一個服務程序通常在一個眾所周知的地址監聽對服務的請求,也就是說,服務進程一直處于休眠狀態,直到一個客戶對這個服務的地址提出了連接請求。在這個時刻,服務程序被“驚醒”并且為客戶提供服務-對客戶的請求作出適當的反應。這一請求 / 相應的過程可以簡單的用圖 2-1 表示。雖然基于連接的服務是設計客戶機 / 服務器應用程序時的標準,但有些服務也是可以通過數據報套接口提供的。

(3) 帶外數據
注意:以下對于帶外數據(也稱為 TCP 緊急數據)的討論,都是基于 BSD 模型而言的。用戶和實現者必須注意,目前有兩種互相矛盾的關于 RFC 793 的解釋,也就是在這基礎上,帶外數據這一概念才被引入的。而且 BSD 對于帶外數據的實現并沒有符合 RFC 1122 定下的主機的要求,為了避免互操作時的問題,應用程序開發者最好不要使用帶外數據,除非是與某一既成事實的服務互操作時所必須的。 Windows Sockets 提供者也必須提供他們的產品對于帶外數據實現的語義的文擋(采用 BSD 方式或者是 RFC 1122 方式)。規定一個特殊的帶外數據語義集已經超出了 Windows Sockets 規范的討論范圍。
流套接口的抽象中包括了帶外數據這一概念,帶外數據是相連的每一對流套接口間一個邏輯上獨立的傳輸通道。帶外數據是獨立于普通數據傳送給用戶的,這一抽象要求帶外數據設備必須支持每一時刻至少一個帶外數據消息被可靠地傳送。這一消息可能包含至少一個字節;并且在任何時刻僅有一個帶外數據信息等候發送。對于僅支持帶內數據的通訊協議來說(例如緊急數據是與普通數據在同一序列中發送的),系統通常把緊急數據從普通數據中分離出來單獨存放。這就允許用戶可以在順序接收緊急數據和非順序接收緊急數據之間作出選擇(非順序接收時可以省去緩存重疊數據的麻煩)。在這種情況下,用戶也可以“偷看一眼”緊急數據。
某一個應用程序也可能喜歡線內處理緊急數據,即把其作為普通數據流的一部分。這可以靠設置套接口選項中的 SO_OOBINLINE 來實現(參見 5.1.21 節, setsockopt() )。在這種情況下,應用程序可能希望確定未讀數據中的哪一些是“緊急”的(“緊急”這一術語通常應用于線內帶外數據)。為了達到這個目的,在 Windows Sockets 的實現中就要在數據流保留一個邏輯記號來指出帶外數據從哪一點開始發送,一個應用程序可以使用 SIOCATMARK ioctlsocket() 命令(參見 5.1.12 節)來確定在記號之前是否還有未讀入的數據。應用程序可以使用這一記號與其對方進行重新同步。
WSAAsyncSelect() 函數可以用于處理對帶外數據到來的通知。
(4)廣播
數據報套接口可以用來向許多系統支持的網絡發送廣播數據包。要實現這種功能,網絡本身必須支持廣播功能,因為系統軟件并不提供對廣播功能的任何模擬。廣播信息將會給網絡造成極重的負擔,因為它們要求網絡上的每臺主機都為它們服務,所以發送廣播數據包的能力被限制于那些用顯式標記了允許廣播的套接口中。廣播通常是為了如下兩個原因而使用的: 1. 一個應用程序希望在本地網絡中找到一個資源,而應用程序對該資源的地址又沒有任何先驗的知識。 2. 一些重要的功能,例如路由要求把它們的信息發送給所有可以找到的鄰機。
被廣播信息的目的地址取決于這一信息將在何種網絡上廣播。 Internet 域中支持一個速記地址用于廣播- INADDR_BROADCAST 。由于使用廣播以前必須捆綁一個數據報套接口,所以所有收到的廣播消息都帶有發送者的地址和端口。
某些類型的網絡支持多種廣播的概念。例如 IEEE802.5 令牌環結構便支持鏈接層廣播指示,它用來控制廣播數據是否通過橋接器發送。 Windows Sockets 規范沒有提供任何機制用來判斷某個應用程序是基于何種網絡之上的,而且也沒有任何辦法來控制廣播的語義。
字節順序
Intel 處理器的字節順序是和 DEC VAX 處理器的字節順序一致的。因此它與 68000 型處理器以及 Internet 的順序是不同的,所以用戶在使用時要特別小心以保證正確的順序。
任何從 Windows Sockets 函數對 IP 地址和端口號的引用和傳送給 Windows Sockets 函數的 IP 地址和端口號均是按照網絡順序組織的,這也包括了 sockaddr_in 結構這一數據類型中的 IP 地址域和端口域(但不包括 sin_family 域)。
考慮到一個應用程序通常用與“時間”服務對應的端口來和服務器連接,而服務器提供某種機制來通知用戶使用另一端口。因此 getservbyname() 函數返回的端口號已經是網絡順序了,可以直接用來組成一個地址,而不需要進行轉換。然而如果用戶輸入一個數,而且指定使用這一端口號,應用程序則必須在使用它建立地址以前,把它從主機順序轉換成網絡順序(使用 htons() 函數)。相應地,如果應用程序希望顯示包含于某一地址中的端口號(例如從 getpeername() 函數中返回的),這一端口號就必須在被顯示前從網絡順序轉換到主機順序(使用 ntohs() 函數)。
由于 Intel 處理器和 Internet 的字節順序是不同的,上述的轉換是無法避免的,應用程序的編寫者應該使用作為 Windows Sockets API 一部分的標準的轉換函數,而不要使用自己的轉換函數代碼。因為將來的 Windows Sockets 實現有可能在主機字節順序與網絡字節順序相同的機器上運行。因此只有使用標準的轉換函數的應用程序是可移植的。
套接口屬性選項
Windows Sockets 規范支持的套接口屬性選項都列在對 setsockopt() 函數和 getsockopt() 函數的敘述中。任何一個 Windows Sockets 實現必須能夠識別所有這些屬性選項,并且對每一個屬性選項都返回合理的數值。每一個屬性選項的缺省值列在下表中:
選項 類型 含義 缺省值 注意事項
SO_ACCEPTCON BOOL 套接口正在監聽。 FALSE
SO_BROADCAST BOOL 套接口被設置為可以 FALSE 發送廣播數據。
SO_DEBUG BOOL 允許 Debug FALSE(*)
S0_DONTLINGER BOOL 如果為真, SO_LINGER 選項被禁止 TRUE
SO_DONTROUTE BOOL 路由被禁止。 FALSE (*)
SO_ERROR int 得到并且清除錯誤狀態。 0
SO_KEEPALIVE BOOL 活躍信息正在被發送。 FALSE
SO_LINGER struct 返回目前的 linger 信息。 l_onoff linger 0FAR *
SO_OOBINLINE BOOL 帶外數據正在普通數據流中被接收。 FALSE
SO_RCVBUF int 接收緩沖區大小。 決定于實現 (*)
SO_REUSEADDR BOOL 該套接口捆綁的地址 FALSE 是否可被其他人使用。
SO_SNDBUF int 發送緩沖區大小。 決定于實現 (*)
SO_TYPE int 套接口類型(如 SOCK_STREAM )。 和套接口被創建時一致
TCP_NODELAY BOOL 禁止采用 Nagle 決定于實現進行合并傳送。
(*) Windows Sockets 實現有可能在用戶調用 setsockopt() 函數時忽略這些屬性,并且在用戶調用 getsockopt() 函數時返回一個沒有變化的值。或者它可能在 setsockopt() 時接受某個值,并且在 getsockopt() 時返回相應的數值,但事實上并沒有在任何地方使用它。
數據庫文件
getXbyY() WSAAyncGetXByY() 這一類的例程是用來得到某種特殊的網絡信息的。 getXbyY() 例程最初(在第一版的 BERKELY UNIX 中)是被設計成一種在文本數據庫中查詢信息的機制。雖然 Windows Sockets 實現可能用不同的方式來得到這些信息,但 Windows Sockets 應用程序要求通過 getXbyY() WSAAyncGetXByY() 這一類例程得到的信息是一致。
Berkeley 套接口的不同
有一些很有限的地方, Windows Sockets API 必須與從嚴格地堅持 Berkeley 傳統風格中解放出來。通常這么做是因為在 Windows 環境中實現的難度。
(1) 套接口數據類型和錯誤數值
Windows Sockets 規范中定義了一個新的數據類型 SOCKET ,這一類型的定義對于將來 Windows Sockets 規范的升級是必要的。例如在 Windows NT 中把套接口作為文件句柄來使用。這一類型的定義也保證了應用程序向 Win/32 環境的可移植性。因為這一類型會自動地從 16 位升級到 32 位。
UNIX 中所有句柄包括套接口句柄,都是非負的短整數,而且一些應用程序把這一假設視為真理。 Windows Sockets 句柄則沒有這一限制,除了 INVALID_SOCKET 不是一個有效的套接口外,套接口可以取從 0 INVALID_SOCKET-1 之間的任意值。
因為 SOCKET 類型是 unsigned ,所以編譯已經存在于 UNIX 環境中的應用程序的源代碼可能會導致 signed/unsigned 數據類型不匹配的警告。
這還意味著,在 socket() 例程和 accept() 例程返回時,檢查是否有錯誤發生就不應該再使用把返回值和 -1 比較的方法,或判斷返回值是否為負(這兩種方法在 BSD 中都是很普通,很合法的途徑)。取而代之的是,一個應用程序應該使用常量 INVALID_SOCKET ,該常量已在 WINSOCK.H 中定義。
例如:
典型的 BSD 風格:
s = socket(...);
if (s == -1) /* of s<0 */
{...}
更優良的風格:
s = socket(...);
if (s == INVALID_SOCKET)
{...}
(2) select() 函數和 FD_*
由于一個套接口不再表示了 UNIX 風格的小的非負的整數, select() 函數在 Windows Sockets API 中的實現有一些變化:每一組套接口仍然用 fd_set 類型來代表,但是它并不是一個位掩碼。整個組的套接口是用了一個套接口的數組來實現的。為了避免潛在的危險,應用程序應該堅持用 FD_XXX 宏來設置,初始化,清除和檢查 fd_set 結構。
(3) 錯誤代碼- errno,h_errno,WSAGetLastError()
Windows Sockets 實現所設置的錯誤代碼是無法通過 errno 變量得到的。另外對于 getXbyY() 這一類的函數,錯誤代碼無法從 h_errno 變量得到。錯誤代碼可以使用 WSAGetLastError() 調用得到。這一函數在 5.3.11 中討論。這個函數在 Windows Sockets 實現中是作為 WIN/32 函數 GetLastError() 的先導函數(最終是一個別名)。這樣做是為了在多線程的進程中為每一線程得到自己的錯誤信息提供可靠的保障。
為了保持與 BSD 的兼容性,應用程序可以加入以下一行代碼:
#define errno WSAGetLastError()
這就保證了用全程的 errno 變量所寫的網絡程序代碼在單線程環境中可以正確使用。當然,這樣做有許多明顯的缺點:如果一個原程序包含了一段代碼對套接口和非套接口函數都用 errno 變量來檢查錯誤,那么這種機制將無法工作。此外,一個應用程序不可能為 errno 賦一個新的值(在 Windows Sockets 中, WSASetLastError() 函數可以做到這一點)。
例如:
典型的 BSD 風格:
r = recv(...);
if (r == -1/* 但請見下文 */
&& errno == EWOULDBLOCK)
{...}
更優良的風格:
r = recv(...);
if (r == -1/* 但請見下文 */
&& WSAGetLastError() == EWOULDBLOCK)
{...}
雖然為了兼容性原因,錯誤常量與 4.3BSD 所提供的一致;應用程序應該盡可能地使用“ WSA ”系列錯誤代碼定義。例如,一個更準確的上面程序片斷的版本應該是:
r = recv(...);
if (r == -1/* 但請見下文 */
&& WSAGetLastError() == WSAEWOULDBLOCK)
{...}
(4) 指針
所有應用程序與 Windows Sockets 使用的指針都必須是 FAR 指針,為了方便應用程序開發者使用, Windows Sockets 規范定義了數據類型 LPHOSTENT
(5) 重命名的函數
有兩種原因 Berkeley 套接口中的函數必須重命名以避免與其他的 API 沖突:
close() closesocket()
Berkeley 套接口中,套接口出現的形式與標準文件描述字相同,所以 close() 函數可以用來和關閉正規文件一樣來關閉套接口。雖然在 Windows Sockets API 中,沒有任何規定阻礙 Windows Sockets 實現用文件句柄來標識套接口,但是也沒有任何規定要求這么做。套接口描述字并不認為是和正常文件句柄對應的 , 而且并不能認為文件操作,例如 read() write() close() 在應用于套接口后不能保證正確工作。套接口必須使用 closesocket() 例程來關閉,用 close() 例程來關閉套接口是不正確的,這樣做的效果對于 Windows Sockets 規范說來也是未知的。
ioctl() iooctlsocket()
許多 C 語言的運行時系統出于與 Windows Sockets 無關的目的使用 ioctl() 例程,所以 Windows Sockets 定義 ioctlsocket() 例程。它被用于實現 BSD 中用 ioctl() fcntl() 實現的功能。
(6) 阻塞例程和 EINPROGRESS
雖然 Windows Sockets 支持關于套接口的阻塞操作,但是這種應用是被強烈反對的 . 如果程序員被迫使用阻塞模式(例如一個準備移植的已有的程序),那么他應該清楚地知道 Windows Sockets 中阻塞操作的語義。有關細節請參見 4.1.1
(7) Windows Sockets 支持的最大套接口數目
一個特定的 Windows Sockets 提供者所支持的套接口的最大數目是由實現確定的。任何一個應用程序都不應假設某個待定數目的套接口可用。這一點在 4.3.15 WSAStartup() 中會被重申。而且一個應用程序可以真正使用的套接口的數目和某一特定的實現所支持的數目是完全無關的。
一個 Windows Sockets 應用程序可以使用的套接口的最大數目是在編譯時由常量 FD_SETSIZE 決定的。這個常量在 select() 函數(參見 4.1.18 )中被用來組建 fd_set 結構。在 WINSOCK.H 中缺省值是 64 。如果一個應用程序希望能夠使用超過 64 個套接口,則編程人員必須在每一個源文件包含 WINSOCK.H 前定義確切的 FD_SET 值。有一種方法可以完成這項工作,就是在工程項目文件中的編譯器選項上加入這一定義。例如在使用 Microsoft C 時加入 -D FD_SETSIZE=128 作為編譯命令的一個命令行參數 . 要強調的是: FD_SET 定義的值對 Windows Sockets 實現所支持的套接口的數目并無任何影響。
(8) 頭文件
為了方便基于 Berkeley 套接口的已有的源代碼的移植, Windows Sockets 支持許多 Berkeley 頭文件。這些 Berkeley 頭文件被包含在 WINSOCK.H 中。所以一個 Windows Sockets 應用程序只需簡單的包含 WINSOCK.H 就足夠了(這也是一種被推薦使用的方法)。
(9)A PI 調用失敗時的返回值
常量 SOCKET_ERROR 是被用來檢查 API 調用失敗的。雖然對這一常量的使用并不是強制性的,但這是推薦的。如下的例子表明了如何使用 SOCKET_ERROR 常量
典型的 BSD 風格:
r = recv(...);
if (r == -1 /* or r < 0 */
&& errno == EWOULDBLOCK)
{...}
更優良的風格:
r = recv(...);
if (r == SOCKET_ERROR
&& WSAGetLastError == WSAEWOULDBLOCK)
{...}
(10) 原始套接口
Windows Sockets 規范并沒有規定 Windows Sockets DLL 必須支持原始套接口-用 SOCK_RAW 打開的套接口。然而 Windows Sockets 規范鼓勵 Windows Sockets DLL 提供原始套接口支持。一個 Windows Sockets 兼容的應用程序在希望使用原始套接口時應該試圖用 socket() 調用(參見 5.1.23 節)來打開套接口。如果這么做失敗了,應用程序則應該使用其他類型的套接口或向用戶報告錯誤。
在多線程 Windows 版本中的 Windows Sockets
Windows Sockets 接口被設計成既能夠在單線程的 Windows 版本(例如 Windows 3.1 )又能夠在占先的多線程 Windows 版本(例如 Windows NT )中使用,在多線程環境中,套接口接口基本上是不變的。但多線程應用程序的作者必須知道,在線程之間同步對套接口的使用是應用程序的責任,而不是 Windows Sockets 實現的責任。這一點在其他形式的 I/O 中管理,例如文件 I/O 中是一樣的。沒有對套接口調用進行同步將導致不可預測的結果。例如,如果有兩個線程同時調用同一套接口進行 send() ,那么數據發送的先后順序就無法保證了。
在一個線程中關閉一個未完成的阻塞的套接口將會導致另一個線程使用同一套接口的阻塞調用出錯( WSAEINTER )返回,就象操作被取消一樣。這也同樣適用于某一個 select() 調用未完成時,應用程序關閉了其中的一個被選擇的套接口。
在占先的多線程 Windows 版本中,并沒有缺省的阻塞鉤子函數。這是因為如果一個單一的應用程序在等待某一操作結束時并不會調用 PeekMessage() GetMessage() 這些會使應用程序產生一個非占先窗口的函數。因此機器在這種情況下不會被阻塞。然而,為了向后的兼容性,在多線程 Windows 版本中, WSASetBlockingHook() 函數也被實現了。任何使用缺省阻塞鉤子的應用程序可以安裝它們自己的阻塞鉤子函數來覆蓋缺省的阻塞鉤子函數。

使用Windows Sockets 1.1編程


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 牛人盗摄一区二区三区视频 | 波多结衣一区二区三区 | 欧美中文字幕在线 | 亚洲一区二区中文字幕 | 德国女人一级毛片免费 | 欧美日韩亚洲国产一区二区三区 | 老子影院午夜伦手机不卡无 | 亚洲资源站资源网在线 | 欧美黄色录像 | 亚洲 欧美 日韩 在线 香蕉 | 亚洲成人av | 羞羞视频免费观看网站 | 成人黄色小视频 | 久久精品中文字幕有码日本 | 亚洲精品中文一区不卡 | 天堂日韩 | 性丰满妇女free性性性 | 爱爱片免费看 | 国产网红福利 | 天天干天天插天天 | 在线观看久草 | 97av麻豆蜜桃一区二区 | 日本不卡免费高清一级视频 | 亚洲国产视频在线观看 | 久久免费福利视频 | 热99re久久精品2久久久 | 日日碰夜夜爽 | 网站久久 | 九九福利视频 | 久久久久久青草大香综合精品 | 亚洲欧美一二三区 | 国产精品久久久久一区二区 | 国产精品久久久久久久伊一 | 免费一级毛毛片 | 色中色官网| 99在线精品日韩一区免费国产 | 国产一级毛片在线 | 六月丁香深爱六月综合激情 | 亚洲视频精品在线观看 | 99精品影视 | 国产福利在线观看 |