8.1.2 非鎖定模式
除了鎖定模式,我們還可考慮采用非鎖定模式的套接字。盡管這種套接字在使用上存在著些許難度,但只要排除了這項(xiàng)困難,它在功能上還是非常強(qiáng)大的。除具備鎖定套接字已有的各項(xiàng)優(yōu)點(diǎn)之外,還進(jìn)行了少許擴(kuò)充,功能更強(qiáng)。程序清單8 - 3向大家展示了如何創(chuàng)建一個套接字,并將其置為非鎖定模式。
程序清單8-3 設(shè)置一個非鎖定套接字
SOCKET s;
unsigned long u1 = 1;
int nRet;
s = SOCKET(AF_INET,SOCK_STREA,0);
nRet = ioctlsocket(s,FIOBIO,(unsigned long *)&ul);
if(nRet == SOCKET_ERROR)
{
?//Failed to put the socket into nonblocking mode
}
將一個套接字置為非鎖定模式之后, Winsock API調(diào)用會立即返回。大多數(shù)情況下,這些調(diào)用都會“失敗”,并返回一個W S A E W O U L D B L O C K錯誤。什么意思呢?它意味著請求的操作在調(diào)用期間沒有時間完成。舉個例子來說,假如在系統(tǒng)的輸入緩沖區(qū)中,尚不存在“待決”的數(shù)據(jù),那么r e c v(接收數(shù)據(jù))調(diào)用就會返回W S A E W O U L D B L O C K錯誤。通常,我們需要重復(fù)調(diào)用同一個函數(shù),直至獲得一個成功返回代碼。在表8 - 2中,我們對常見Wi n s o c k調(diào)用返
回的W S A E W O U L D B L O C K錯誤的含義進(jìn)行了總結(jié)。
由于非鎖定調(diào)用會頻繁返回W S A E W O U L D B L O C K錯誤,所以在任何時候,都應(yīng)仔細(xì)檢查所有返回代碼,并作好“失敗”的準(zhǔn)備。許多程序員易犯的一個錯誤便是連續(xù)不停地調(diào)用一個函數(shù),直到它返回成功的消息為止。例如,假定在一個緊湊的循環(huán)中不斷地調(diào)用r e c v,以讀入2 0 0個字節(jié)的數(shù)據(jù),那么與使用前述的M S G _ P E E K標(biāo)志來“輪詢”一個鎖定套接字相比,
前一種做法根本沒有任何優(yōu)勢可言。為此, Wi n s o c k的套接字I / O模型可幫助應(yīng)用程序判斷一個套接字何時可供讀寫。
鎖定和非鎖定套接字模式都存在著優(yōu)點(diǎn)和缺點(diǎn)。其中,從概念的角度說,鎖定套接字更易使用。但在應(yīng)付建立連接的多個套接字時,或在數(shù)據(jù)的收發(fā)量不均,時間不定時,卻顯得極難管理。而另一方面,假如需要編寫更多的代碼,以便在每個Wi n s o c k調(diào)用中,對收到一個W S A E W O U L D B L O C K錯誤的可能性加以應(yīng)付,那么非鎖定套接字便顯得有些難于操作。在這些情況下,可考慮使用“套接字I / O模型”,它有助于應(yīng)用程序通過一種異步方式,同時對一個或多個套接字上進(jìn)行的通信加以管理。
表8-2 非鎖定套接字上的W S A E W O U L D B L O C K錯誤函數(shù)名說明
W S A A c c e p t和a c c e p t?? 應(yīng)用程序沒有收到連接請求。再次調(diào)用,便可檢查連接情況
c l o s e s o c k e t??????????大多數(shù)情況下,這個錯誤意味著已隨S O _ L I N G E R選項(xiàng)一道,調(diào)用了s e t s o c k o p t,而且已設(shè)定了一個非零的超時值
W S A C o n n e c t和c o n n e c t???????應(yīng)用程序已初始化。再次調(diào)用,便可檢查是否完成
W S A R e c v、r e c v、W S A R e c v F r o m和r e c v f r o m 沒有收到數(shù)據(jù)。稍后再次檢查
W S A S e n d、s e n d、W S A S e n d To和s e n d t o 外出數(shù)據(jù)無緩沖區(qū)可用。稍后再試