WinSock API
WinSock API
Socket介面是網路編程(通常是TCP/IP協議,也可以是其他協議)的API。最早的Socket介面是Berkeley介面,在Unix操作系統中實現。WinSock也是一個基於Socket模型的API,在Microsoft Windows操作系統類中使用。它在Berkeley介面函數的基礎之上,還增加了基於消息驅動機制的Windows擴展函數。Winscok1.1隻支持TCP/IP網路,WinSock2.0增加了對更多協議的支持。這裡,討論TCP/IP網路上的API。
第一類是WinSock API包含的Berkeley socket函數。這類函數分兩部分。第一部分是用於網路I/O的函數,如
另一部分是不涉及網路I/O、在本地端完成的函數,如
bind、getpeername、getsockname、getsocketopt、htonl、htons、inet_addr、inet_nton
第二類是檢索有關域名、通信服務和協議等Internet信息的資料庫函數,如
getprotolbynumber、getserverbyname、getservbyport。
第三類是Berkekley socket常式的Windows專用的擴展函數,如gethostbyname對應的WSAAsynGetHostByName(其他資料庫函數除了gethostname都有非同步版本),select對應的WSAAsynSelect,判斷是否阻塞的函數WSAIsBlocking,得到上一次Windsock API錯誤信息的WSAGetLastError,等等。
從另外一個角度,這些函數又可以分為兩類,一是阻塞函數,一是非阻塞函數。
所謂阻塞函數,是指其完成指定的任務之前不允許程序調用另一個函數,在Windows下還會阻塞本線程消息的發送。所謂非阻塞函數,是指操作啟動之後,如果可以立即得到結果就返回結果,否則返回表示結果需要等待的錯誤信息,不等待任務完成函數就返回。
首先,非同步函數是非阻塞函數;
其次,獲取遠地信息的資料庫函數是阻塞函數(因此,WinSock提供了其非同步版本);
在Berkeley socket函數部分中,不涉及網路I/O、本地端工作的函數是非阻塞函數;
在Berkeley socket函數部分中,網路I/O的函數是可阻塞函數,也就是它們可以阻塞執行,也可以不阻塞執行。這些函數都使用了一個socket,如果它們使用的socket是阻塞的,則這些函數是阻塞函數;如果它們使用的socket是非阻塞的,則這些函數是非阻塞函數。
創建一個socket時,可以指定它是否阻塞。在預設情況下,Berkerley的Socket函數和WinSock都創建“阻塞”的socket。阻塞socket通過使用select函數或者WSAAsynSelect函數在指定操作下變成非阻塞的。WSAAsyncSelect函數原型如下。
int WSAAsyncSelect(
SOCKET s,
HWND hWnd,
u_int wMsg,
long lEvent
);
其中,參數1指定了要操作的socket句柄;參數2指定了一個窗口句柄;參數3指定了一個消息,參數4指定了網路事件,可以是多個事件的組合,如:
FD_READ 準備讀
FD_WRITE 準備寫
FD_OOB 帶外數據到達
FD_ACCEPT 收到連接
FD_CONNECT 完成連接
FD_CLOSE 關閉socket。
用OR操作組合這些事件值,如FD_READ|FD_WRITE
WSAAsyncSelect函數表示對socket s監測lEvent指定的網路事件,如果有事件發生,則給窗口hWnd發送消息wMsg。
假定應用程序的一個socket s指定了監測FD_READ事件,則在FD_READ事件上變成非阻塞的。當read函數被調用時,不管是否讀到數據都馬上返回,如果返回一個錯誤信息表示還在等待,則在等待的數據到達后,消息wMsg發送給窗口hWnd,應用程序處理該消息讀取網路數據。
對於非同步函數的調用,以類似的過程最終得到結果數據。以gethostbyname的非同步版本的使用為例進行說明。該函數原型如下:
HANDLE WSAAsyncGetHostByName(
HWND hWnd,
u_int wMsg,
const char FAR *name,
char FAR *buf,
int buflen
);
在調用WSAAsyncGetHostByName啟動操作時,不僅指定主機名字name,還指定了一個窗口句柄hWnd,一個消息ID wMsg,一個緩衝區及其長度。如果不能立即得到主機地址,則返回一個錯誤信息表示還在等待。當要的數據到達時,WinSock DLL給窗口hWnd發送消息wMsg告知得到了主機地址,窗口過程從指定的緩衝區buf得到主機地址。
使用非同步函數或者非阻塞的socket,主要是為了不阻塞本線程的執行。在多進程或者多線程的情況下,可以使用兩個線程通過同步手段來完成非同步函數或者非阻塞函數的功能。