新聞中心
非阻塞模式是網絡編程中常見的一種模式,其目的是為了提高程序的并發(fā)處理能力。非阻塞模式將socket設置成非阻塞模式,使得程序在接收數據時不必等待,而是可以繼續(xù)執(zhí)行其他任務,從而達到同時處理多個請求的目的。在Linux下,accept函數可以實現非阻塞模式,本文將詳細介紹。

10年積累的網站建設、做網站經驗,可以快速應對客戶對網站的新想法和需求。提供各種問題對應的解決方案。讓選擇我們的客戶得到更好、更有力的網絡服務。我雖然不認識你,你也不認識我。但先網站制作后付款的網站建設流程,更有浪卡子免費網站建設讓你可以放心的選擇與我們合作。
1. accept函數的概述
accept函數是Linux下的網絡編程函數之一,用于接收客戶端發(fā)來的連接請求,生成一個新的socket,從而和客戶端進行通信。accept函數的定義如下:
“`
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
“`
其中,sockfd表示服務端socket的文件描述符,addr和addrlen用于存儲客戶端地址信息。accept函數返回的是新生成的socket的文件描述符。
2. 非阻塞模式的實現
在Linux下,通過fcntl函數可以將socket設置成非阻塞模式。fcntl函數的定義如下:
“`
int fcntl(int sockfd, int cmd, … /* arg */ );
“`
其中,sockfd表示需要設置的socket的文件描述符,cmd表示控制命令,arg表示命令參數。針對accept函數,需要使用以下命令將socket設置成非阻塞模式:
“`
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK);
“`
這條語句將socket的控制命令設置為F_SETFL,參數為fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK。其中,fcntl(sockfd, F_GETFL, 0)表示獲取socket的控制命令,以便于在原有基礎上進行修改;O_NONBLOCK表示將socket設置成非阻塞模式。
將socket設置成非阻塞模式后,accept函數不再是一個阻塞函數。如果沒有客戶端連接請求到達,accept函數會立即返回-1,并設置errno為EWOULDBLOCK或EAGN,表示當前沒有連接請求。如果有客戶端連接請求到達,accept函數會返回一個新的socket的文件描述符,用于和客戶端進行通信。
在非阻塞模式下,需要使用循環(huán)不斷地調用accept函數,直到有新的連接請求到達。該循環(huán)中,可以使用select函數來監(jiān)聽多個socket的狀態(tài),從而實現同時監(jiān)聽多個連接請求的功能。
3. 非阻塞模式的優(yōu)缺點
非阻塞模式相比于阻塞模式有以下優(yōu)點:
(1)提高了程序的并發(fā)處理能力。當程序遇到阻塞操作時,就需要等待該操作完成后才能繼續(xù)執(zhí)行其他任務。而在非阻塞模式下,可以不必等待某個操作完成,而是可以繼續(xù)執(zhí)行其他任務,從而提高程序的并發(fā)處理能力。
(2)減少了系統(tǒng)資源的占用。在多線程編程中,如果每個線程都使用阻塞模式,則系統(tǒng)需要為每個線程分配一定的資源,從而導致系統(tǒng)資源的浪費。而在非阻塞模式下,可以使用一個線程處理多個請求,從而減少了系統(tǒng)資源的占用。
(3)提高了響應速度。非阻塞模式下,可以通過設置超時時間來避免程序一直等待某個操作完成而導致的響應速度過慢的情況。
但是,非阻塞模式也存在一些缺點:
(1)程序實現更加復雜。非阻塞模式需要程序不斷地輪詢socket狀態(tài),從而實現監(jiān)聽多個連接請求的功能。這會導致程序實現更加復雜,代碼也更容易出錯。
(2)處理數據不方便。在非阻塞模式下,需要不斷地輪詢socket狀態(tài),從而可能導致無法一次性讀取所有數據。這就需要程序不斷地處理數據,才能保證數據能夠正確地被接收和處理。
4.
非阻塞模式是一種常見的網絡編程模式,可以提高程序的并發(fā)處理能力和響應速度。在Linux下,可以通過將socket設置成非阻塞模式,結合select函數,實現同時監(jiān)聽多個連接請求的功能。但是,非阻塞模式也存在一些缺點,需要在實際使用時進行權衡和取舍。
成都網站建設公司-創(chuàng)新互聯(lián)為您提供網站建設、網站制作、網頁設計及定制高端網站建設服務!
linux網絡編程,為什么要將文件描述符設置成非阻塞模式
非阻塞IO 和阻塞IO:
在網絡編程中對于一個網絡句柄會遇到阻塞IO 和非阻塞IO 的概念, 這里對于這兩種socket 先做一下說明:
基本概念:
阻塞IO::
socket 的阻塞模式意味著必須要做完IO 操作(包括錯誤)才會
返回。
非阻塞IO::
非阻塞模式下無論操作是否完成都會立刻返回,需要通過其他方
式來判斷具體操作是否成功。(對于connect,accpet操作,通過select判斷,
對于recv,recvfrom,send,sendto通過返回值+錯誤碼來判斷)
IO模式設置:
SOCKET
對于一個socket 是阻塞模式還是非阻塞模式的處理方法::
方法::
用fcntl 設置;用F_GETFL獲取flags,用F_SETFL設置flags|O_NONBLOCK;
同時,recv,send 時使用非阻塞的方式讀取和發(fā)送消息,即flags設置為MSG_DONTWAIT
實現
fcntl 函數可以將一個socket 句柄設置成非阻塞模式:
flags = fcntl(sockfd, F_GETFL, 0);//獲取文件的flags值。
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); //設置成非阻塞模式;
flags = fcntl(sockfd,F_GETFL,0);
fcntl(sockfd,F_SETFL,flags&~O_NONBLOCK); //設置成阻塞模式;
并在接收和發(fā)送數據時:
將recv, send 函數的最后有一個flag 參數設置成MSG_DONTWAIT
recv(sockfd, buff, buff_size,MSG_DONTWAIT); //非阻塞模式的消息仔租發(fā)送
send(scokfd, buff, buff_size, MSG_DONTWAIT); //非阻塞模式的消息接受
普通文件
對于文件的阻塞模式還是非阻塞模式::
方法1、open時,使用O_NONBLOCK;
方法2、fcntl設置,使用F_SETFL,flags|O_NONBLOCK;
消息隊列
對于消息隊列消息的發(fā)送與接受::
//非阻塞 msgsnd(sockfd,msgbuf,msgsize(不包含類型大小),IPC_NOWAIT)
//阻塞 msgrcv(scokfd,msgbuf,msgsize(**),msgtype,IPC_NOWAIT);
讀
阻塞與非阻塞讀的區(qū)別: //
阻塞和非阻塞
的區(qū)別在于沒有數據到達的時候是否立刻返回.
讀(read/recv/msgrcv):
讀的本質來說其實不能是讀,在實際中, 具體的接收數據不是由這些調用來進行,是由于系統(tǒng)底層自動完成的。read 也好,recv 也好只負責把數據從底層緩沖copy 到我們指肢戚基定的位置.
對于讀來說(read, 或者recv) ::
阻塞情況下::
在阻塞條件下,read/recv/msgrcv的行為::
、如果沒有發(fā)現數據在網絡緩沖中會一直等待,
、當發(fā)現有數據的時候會把數據讀到用戶指定的緩沖區(qū),但是如果這個時候讀到的數歷謹據量比較少,比參數中指定的長度要小,read 并不會一直等待下去,而是立刻返回。
read 的原則::是數據在不超過指定的長度的時候有多少讀多少,沒有數據就會一直等待。
所以一般情況下::我們讀取數據都需要采用循環(huán)讀的方式讀取數據,因為一次read 完畢不能保證讀到我們需要長度的數據,
read 完一次需要判斷讀到的數據長度再決定是否還需要再次讀取。
非阻塞情況下::
在非阻塞的情況下,read 的行為::
、如果發(fā)現沒有數據就直接返回,
、如果發(fā)現有數據那么也是采用有多少讀多少的進行處理.
所以::read 完一次需要判斷讀到的數據長度再決定是否還需要再次讀取。
對于讀而言:: 阻塞和非阻塞的區(qū)別在于沒有數據到達的時候是否立刻返回.
recv 中有一個MSG_WAITALL 的參數::
recv(sockfd, buff, buff_size, MSG_WAITALL),
在正常情況下recv 是會等待直到讀取到buff_size 長度的數據,但是這里的WAITALL 也只是盡量讀全,在有中斷的情況下recv 還是可能會被打斷,造成沒有讀完指定的buff_size的長度。
所以即使是采用recv + WAITALL 參數還是要考慮是否需要循環(huán)讀取的問題,在實驗中對于多數情況下recv (使用了MSG_WAITALL)還是可以讀完buff_size,
所以相應的性能會比直接read 進行循環(huán)讀要好一些。
注意:: //使用MSG_WAITALL時,sockfd必須處于阻塞模式下,否則不起作用。
//所以MSG_WAITALL不能和MSG_NONBLOCK同時使用。
要注意的是使用MSG_WAITALL的時候,sockfd 必須是處于阻塞模式下,否則WAITALL不能起作用。
寫
阻塞與非阻塞寫的區(qū)別: //
寫(send/write/msgsnd)::
寫的本質也不是進行發(fā)送操作,而是把用戶態(tài)的數據copy 到系統(tǒng)底層去,然后再由系統(tǒng)進行發(fā)送操作,send,write返回成功,只表示數據已經copy 到底層緩沖,而不表示數據已經發(fā)出,更不能表示對方端口已經接收到數據.
對于write(或者send)而言,
阻塞情況下:: //阻塞情況下,write會將數據發(fā)送完。(不過可能被中斷)
在阻塞的情況下,是會一直等待,直到write 完,全部的數據再返回.這點行為上與讀操作有所不同。
原因::
讀,究其原因主要是讀數據的時候我們并不知道對端到底有沒有數據,數據是在什么時候結束發(fā)送的,如果一直等待就可能會造成死循環(huán),所以并沒有去進行這方面的處理;
寫,而對于write, 由于需要寫的長度是已知的,所以可以一直再寫,直到寫完.不過問題是write 是可能被打斷嗎,造成write 一次只write 一部分數據, 所以write 的過程還是需要考慮循環(huán)write, 只不過多數情況下一次write 調用就可能成功.
非阻塞寫的情況下:: //
非阻塞寫的情況下,是采用可以寫多少就寫多少的策略.與讀不一樣的地方在于,有多少讀多少是由網絡發(fā)送的那一端是否有數據傳輸到為標準,但是對于可以寫多少是由本地的網絡堵塞情況為標準的,在網絡阻塞嚴重的時候,
網絡層
沒有足夠的內存來進行寫操作,這時候就會出現寫不成功的情況,阻塞情況下會盡可能(有可能被中斷)等待到數據全部發(fā)送完畢, 對于非阻塞的情況就是一次寫多少算多少,沒有中斷的情況下也還是會出現write 到一部分的情況.
如何linux 程序中啟用其他進程,非阻塞,非popen
在唯塵兆Linux程序中啟動其他進程可以用system函數,這個函數會等待它啟動的那個程序結束才返回,所以它是一個阻塞調用。還有一種非阻塞的啟動外部程序的方法,指租稍微復雜一點,是運用Linux的exec系列函數,之所以說系列函數是因為有不同的變種,只是參數的形式不同而已,其實完全是一樣的,exec系列函數的行為是將當前進程替換成要啟動的那個新進程,這里的當前進程就是你編寫的程序,新進程啟動后調用exec函數的進程就不存在了,exec系列函數調用之后的代碼也不會再執(zhí)行了。所以,exec系列函數的正確使用方法是在程序中進行fork調用復制進程,然后把exec函數的調用語句放在fork的子進程里面,注兄山意子進程中exec函數調用的后面就不要寫其他功能的代碼了,因為exec函數后面的語句不會被執(zhí)行。
關于linux accept非阻塞的介紹到此就結束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關注本站。
四川成都云服務器租用托管【創(chuàng)新互聯(lián)】提供各地服務器租用,電信服務器托管、移動服務器托管、聯(lián)通服務器托管,云服務器虛擬主機租用。成都機房托管咨詢:13518219792
創(chuàng)新互聯(lián)(www.cdcxhl.com)擁有10多年的服務器租用、服務器托管、云服務器、虛擬主機、網站系統(tǒng)開發(fā)經驗、開啟建站+互聯(lián)網銷售服務,與企業(yè)客戶共同成長,共創(chuàng)價值。
文章標題:Linux下accept函數的非阻塞模式(linuxaccept非阻塞)
當前地址:http://fisionsoft.com.cn/article/cosoeih.html


咨詢
建站咨詢
