1. socket阻塞和非阻塞的區別
阻塞socket和非阻塞socket的區別:
1、讀操作
對於阻塞的socket,當socket的接收緩沖區中沒有數據時,read調用會一直阻塞住,直到有數據到來才返回。當socket緩沖區中的數據量小於期望讀取的數據量時,返回實際讀取的位元組數。當sockt的接收緩沖區中的數據大於期望讀取的位元組數時,讀取期望讀取的位元組數,返回實際讀取的長度。
對於非阻塞socket而言,socket的接收緩沖區中有沒有數據,read調用都會立刻返回。接收緩沖區中有數據時,與阻塞socket有數據的情況是一樣的,如果接收緩沖區中沒有數據,則返回錯誤號為EWOULDBLOCK,表示該操作本來應該阻塞的,但是由於本socket為非阻塞的socket,因此立刻返回,遇到這樣的情況,可以在下次接著去嘗試讀取。如果返回值是其它負值,則表明讀取錯誤。
2、寫操作
對於寫操作write,原理是類似的,非阻塞socket在發送緩沖區沒有空間時會直接返回錯誤號EWOULDBLOCK,表示沒有空間可寫數據,如果錯誤號是別的值,則表明發送失敗。如果發送緩沖區中有足夠空間或者是不足以拷貝所有待發送數據的空間的話,則拷貝前面N個能夠容納的數據,返回實際拷貝的位元組數。
而對於阻塞Socket而言,如果發送緩沖區沒有空間或者空間不足的話,write操作會直接阻塞住,如果有足夠空間,則拷貝所有數據到發送緩沖區,然後返回.
3、建立連接
阻塞方式下,connect首先發送SYN請求道伺服器,當客戶端收到伺服器返回的SYN的確認時,則connect返回.否則的話一直阻塞.
非阻塞方式,connect將啟用TCP協議的三次握手,但是connect函數並不等待連接建立好才返回,而是立即返回。返回的錯誤碼為EINPROGRESS,表示正在進行某種過程.
4、接收
連接
對於阻塞方式的傾聽socket,accept在連接隊列中沒有建立好的連接時將阻塞,直到有可用的連接,才返回。
非阻塞傾聽socket,在有沒有連接時都立即返回,沒有連接時,返回的錯誤碼為EWOULDBLOCK,表示本來應該阻塞
2. php 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中的數據到剩餘空間里
如果是非阻塞模式下:
在調用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() 函數。當調用該函數時,套接字會自動地設置為非阻塞方式: