導航:首頁 > 操作系統 > linuxsocket設置非阻塞

linuxsocket設置非阻塞

發布時間:2025-02-20 20:30:06

linux網路編程中阻塞和非阻塞socket的區別

阻塞socket和非阻塞socket的區別:
1、讀操作
對於阻塞的socket,當socket的接收緩沖區中沒有數據時,read調用會一直阻塞住,直到有數據到來才返回。當socket緩沖區中的數據量小於期望讀取的數據量時,返回實際讀取的位元組數。當sockt的接收緩沖區中的數據大於期望讀取的位元組數時,讀取期望讀取的位元組數,返回實際讀取的長度。
對於非阻塞socket而言,socket的接收緩沖區中有沒有數據,read調用都會立刻返回。接收緩沖區中有數據時,與阻塞socket有數據的情況是一樣的,如果接收緩沖區中沒有數據,則返回錯誤號為EWOULDBLOCK,表示該操作本來應該阻塞的,但是由於本socket為非阻塞的socket,因此立刻返回,遇到這樣的情況,可以在下次接著去嘗試讀取。如果返回值是其它負值,則表明讀取錯誤。
因此,非阻塞的rea調用一般這樣寫:
if ((nread = read(sock_fd, buffer, len)) < 0)
{
if (errno == EWOULDBLOCK)
{
return 0; //表示沒有讀到數據
}else return -1; //表示讀取失敗
}else return nread;讀到數據長度
2、寫操作
對於寫操作write,原理是類似的,非阻塞socket在發送緩沖區沒有空間時會直接返回錯誤號EWOULDBLOCK,表示沒有空間可寫數據,如果錯誤號是別的值,則表明發送失敗。如果發送緩沖區中有足夠空間或者是不足以拷貝所有待發送數據的空間的話,則拷貝前面N個能夠容納的數據,返回實際拷貝的位元組數。
而對於阻塞Socket而言,如果發送緩沖區沒有空間或者空間不足的話,write操作會直接阻塞住,如果有足夠空間,則拷貝所有數據到發送緩沖區,然後返回.
非阻塞的write操作一般寫法是:
int write_pos = 0;
int nLeft = nLen;
while (nLeft > 0)
{
int nWrite = 0;
if ((nWrite = write(sock_fd, data + write_pos, nLeft)) <= 0)
{
if (errno == EWOULDBLOCK)
{
nWrite = 0;
}else return -1; //表示寫失敗
}
nLeft -= nWrite;
write_pos += nWrite;
}
return nLen;
3、建立連接
阻塞方式下,connect首先發送SYN請求道伺服器,當客戶端收到伺服器返回的SYN的確認時,則connect返回.否則的話一直阻塞.
非阻塞方式,connect將啟用TCP協議的三次握手,但是connect函數並不等待連接建立好才返回,而是立即返回。返回的錯誤碼為EINPROGRESS,表示正在進行某種過程.
4、接收連接
對於阻塞方式的傾聽socket,accept在連接隊列中沒有建立好的連接時將阻塞,直到有可用的連接,才返回。
非阻塞傾聽socket,在有沒有連接時都立即返回,沒有連接時,返回的錯誤碼為EWOULDBLOCK,表示本來應該阻塞。
無阻塞的設置方法
方法一:fcntl
int flag;
if (flag = fcntl(fd, F_GETFL, 0) <0) perror("get flag");
flag |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flag) < 0)
perror("set flag");
方法二:ioctl
int b_on = 1;
ioctl (fd, FIONBIO, &b_on);

Ⅱ recv是阻塞還是非阻塞的

網路編程函數如recv是阻塞(同步)還是非阻塞(非同步)取決於在調用recv函數前創建的套接字socket是阻塞還是非阻塞。socket默認創建時設定為阻塞模式;若要將socket設定為非阻塞模式,可以在socket創建時設定為非阻塞模式,那麼函數recv就是非阻塞的。
可以通過一下幾種方法設定socket為非阻塞:
1.linux平台可以在利用socket()函數創建socket時指定socket是非同步(非阻塞)的:
int socket(int domain, int type, int protocol);
在參數type中設置SOCK_NONBLOCK標志即可,例如:
int s = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
2.windows和linux平台accept()函數返回的socekt也是阻塞的,linux另外提供了一個accept4()函數,可以直接將socket設置為非阻塞模式:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
只要將accept4()最後一個參數flags設置成SOCK_NONBLOCK即可。

3.除了在創建socket時,將socket設置為非阻塞模式,還可以通過以下函數來設置:

linux平台可以調用fcntl()或ioctl()函數,例如:
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK);
ioctl(sockfd, FIONBIO, 1); //1:非阻塞 0:阻塞
windows平台可調用ioctlsocket函數:

int ioctlsocket(
_In_ SOCKET s,
_In_ long cmd,
_Inout_ u_long *argp
);
將cmd參數設置為FIONBIO,*argp=0即設置成阻塞模式,而*argp非0即可設置成非阻塞模式。但windows平台一個地方需要注意,如果對一個socket調用了WSAAsyncSelect()或WSAEventSelect()函數後,你再調用ioctlsocket()函數將該socket設置為阻塞模式,則會失敗,必須先調用WSAAsyncSelect()設置lEvent參數為0或調用WSAEventSelect()設置lNetworkEvents參數為0來分別禁用WSAAsyncSelect()或WSAEventSelect(),再次調用ioctlsocket()將該socket設置成阻塞模式才會成功。因為調用WSAAsyncSelect()或WSAEventSelect()函數會自動將socket設置成非阻塞模式。

Ⅲ 伺服器編程心得(四)—— 如何將socket設置為非阻塞模式

在伺服器編程中,設置socket為非阻塞模式是提高性能的關鍵技術之一。不同操作系統上實現這一功能的方法有所差異。在Windows平台上,無論是使用socket()函數還是WSASocket()函數創建的socket都是默認為阻塞模式的。

相比之下,Linux平台上在使用socket()函數創建socket時,可以通過在type參數中設置SOCK_NONBLOCK標志來創建一個非阻塞模式的socket。例如:

在Linux上,通過將SOCK_NONBLOCK標志設置為SOCK_NONBLOCK,即可創建一個非阻塞模式的socket。

在Windows和Linux平台上的accept()函數返回的socket同樣是阻塞模式的,不過Linux額外提供了一個accept4()函數,該函數可以直接將返回的socket設置為非阻塞模式。實現方法只需將accept4()函數的最後一個參數flags設置為SOCK_NONBLOCK即可。

除了在創建socket時設置非阻塞模式外,還可以通過調用特定的API函數來實現。在Linux平台上,可以使用fcntl()或者ioctl()函數來修改socket的阻塞屬性。例如:

通過調用fcntl()函數或者ioctl()函數,即可將Linux平台上的socket設置為非阻塞模式。在設置非阻塞模式時,需要確保在接收和發送數據時使用了MSG_DONTWAIT標志,即在recv、recvfrom和send、sendto函數調用時,將flag參數設置為MSG_DONTWAIT。然而,根據Linux手冊的說明,設置recv()函數的flags標識位為MSG_DONTWAIT或者通過fcntl()函數設置O_NONBLOCK標識,已經足夠實現非阻塞操作,無需同時設定兩種方式。

在Windows平台上,可以通過調用ioctlsocket函數來改變socket的阻塞模式。將cmd參數設置為FIONBIO,同時將*argp參數設置為0或非0,即可分別設置socket為阻塞模式或非阻塞模式。需要注意的是,如果對socket調用了WSAAsyncSelect()或WSAEventSelect()函數後,再嘗試使用ioctlsocket()將socket設置為非阻塞模式,將會失敗。解決此問題,需要先通過設置lEvent參數為0或設置lNetworkEvents參數為0來禁用WSAAsyncSelect()或WSAEventSelect(),然後再調用ioctlsocket()設置socket為阻塞模式。

在實際項目中,有的前輩可能會在一個循環里調用fcntl()或者ioctlsocket()函數來改變socket的阻塞模式。然而,這是否必要,仍有待驗證。建議讀者根據實際需求和項目要求選擇合適的方法。

如果想系統地學習上述知識,推薦閱讀尹聖雨的《TCP/IP 網路編程》這本書,它兼顧了Windows和Linux兩個平台,使用C語言和操作系統的Socket API,能夠幫助讀者理解網路編程的基本概念和實現方法。對於更深入的高性能網路框架和設計,可以參考游雙老師的《Linux 高性能伺服器編程》一書。

此外,作者也出版了一本書《C++伺服器開發精髓》,涵蓋了從客戶端到伺服器、從Windows到Linux的經驗總結,包括C++開發編譯調試技術、多線程編程、網路故障排查、通信協議設計、高性能網路框架設計、服務框架設計、服務組件開發等知識。獲取更多書籍信息,請參考相關鏈接。

閱讀全文

與linuxsocket設置非阻塞相關的資料

熱點內容
壓縮機不是怕液體嗎 瀏覽:353
程序員吃飯手抖 瀏覽:987
熱釋紅外感測器單片機 瀏覽:202
部署h5源碼 瀏覽:255
win7pythonvim 瀏覽:269
怎麼在伺服器後台跑fortran 瀏覽:728
人物繪pdf 瀏覽:530
pythonsound 瀏覽:969
擺拍app哪個好 瀏覽:216
光遇伺服器爆滿該怎麼辦 瀏覽:811
我的世界怎麼做一個空島伺服器 瀏覽:791
移動協調如何設置伺服器地址 瀏覽:53
哪裡可以刪除不需要安裝的app 瀏覽:52
serato文件夾怎麼刪除 瀏覽:369
小雨游戲解壓視頻 瀏覽:158
ttf如何在伺服器上安裝 瀏覽:402
電腦文件夾共享使用什麼協議 瀏覽:49
芭蕾舞和程序員哪個好 瀏覽:211
常用單片機介面 瀏覽:621
單片機軟體設計原理 瀏覽:72