介紹
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的函式,如
accept、closesocket、connect、recv、recvfrom、select、send、sendto
另一部分是不涉及網路I/O、在本地端完成的函式,如
bind、getpeername、getsockname、getsocketopt、htonl、htons、inet_addr、inet_nton
ioctlsocket、listen、ntohl、ntohs、setsocketopt、shutdown、socket等
第二類是檢索有關域名、通信服務和協定等Internet信息的資料庫函式,如
gethostbyaddr、gethostbyname、gethostname、getprotolbyname
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,主要是為了不阻塞本執行緒的執行。在多進程或者多執行緒的情況下,可以使用兩個執行緒通過同步手段來完成異步函式或者非阻塞函式的功能。