天天看點

看到關于socket非阻塞模式設定方式記錄一下。

關于socket的阻塞與非阻塞模式以及它們之間的優缺點,這已經沒什麼可言的;我打個很簡單的比方,如果你調用socket send函數時;

如果是阻塞模式下:

send先比較待發送資料的長度len和套接字s的發送緩沖的長度,如果len大于s的發送緩沖區的長度,該函數傳回SOCKET_ERROR;如果len小于或者等于s的發送緩沖區的長度,那麼send先檢查協定是否正在發送s的發送緩沖中的資料,如果是就等待協定把資料發送完,如果協定還沒有開始發送s的發送緩沖中的資料或者s的發送緩沖中沒有資料,那麼 send就比較s的發送緩沖區的剩餘空間和len,如果len大于剩餘空間大小,send就一直等待協定把s的發送緩沖中的資料發送完,如果len小于剩餘空間大小send就僅僅把buf中的資料copy到剩餘空間裡

如果是非阻塞模式下:

在調用socket send函數時,如果能寫到socket緩沖區時,就寫資料并傳回實際寫的位元組數目,當然這個傳回的實際值可能比你所要寫的資料長度要小些(On nonblocking stream oriented sockets, the number of bytes written can be between 1 and the requested length, depending on buffer availability on both the client and server computers),如果不可寫的話,就直接傳回SOCKET_ERROR了,是以沒有等待的過程。。

經過上面的介紹後,下面介紹如何設定socket的非阻塞模式:

當使用socket()函數和WSASocket()函數建立套接字時,預設都是阻塞的。在建立套接字之後,通過調用ioctlsocket()函數,将該套接字設定為非阻塞模式。

//-------------------------

// Set the socket I/O mode: In this case FIONBIO

// enables or disables the blocking mode for the

// socket based on the numerical value of iMode.

// If iMode = 0, blocking is enabled;

// If iMode != 0, non-blocking mode is enabled.

u_long iMode = 1;  //non-blocking mode is enabled.

ioctlsocket(m_socket, FIONBIO, &iMode); //設定為非阻塞模式

套接字設定為非阻塞模式後,在調用Windows Sockets API函數時,調用函數會立即傳回。大多數情況下,這些函數調用都會調用“失敗”,并傳回WSAEWOULDBLOCK錯誤代碼。說明請求的操作在調用期間内沒有時間完成。通常,應用程式需要重複調用該函數,直到獲得成功傳回代碼。 不同的Windows Sockets API函數,在調用失敗時傳回的WSAEWOULDBLOCK錯誤代碼具有不同的含義

需要說明的是并非所有的 Windows Sockets API 在非阻塞模式下調用,都會傳回 WSAEWOULDBLOCK 錯誤。例如,以非阻塞模式的套接字為參數調用 bind() 函數時,就不會傳回該錯誤代碼。當然,在調用 WSAStartup() 函數時更不會傳回該錯誤代碼,因為該函數是應用程式第一調用的函數,當然不會傳回這樣的錯誤代碼。

要将套接字設定為非阻塞模式,除了使用 ioctlsocket() 函數之外,還可以使用 WSAAsyncselect() 和 WSAEventselect() 函數。當調用該函數時,套接字會自動地設定為非阻塞方式:

The WSAAsyncSelect function automatically sets socket s to nonblocking mode, regardless of the value of lEvent .

The WSAEventSelect function automatically sets socket s to nonblocking mode, regardless of the value of lNetworkEvents .

繼續閱讀