導航:首頁 > 操作系統 > linuxrecv非阻塞

linuxrecv非阻塞

發布時間:2023-02-06 12:48:57

A. recv函數返回什麼值

recv函數返回其實際的位元組數,如果recv在時出錯,那麼它返回SOCKET_ERROR。如果recv函數在等待協議接收數據時網路中斷了,那麼它返回0。

擴展閱讀,linux recv函數詳解:

1 #include <sys/socket.h>
2 ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags);
recv 的前3個參數等同於read函數。

flags參數值為0或:

flags
說明
recv
send

MSG_DONTWAIT
僅本操作非阻塞

MSG_OOB 發送或接收帶外數據

MSG_PEEK
窺看外來消息

MSG_WAITALL
等待所有數據

recv函數解析:

sockfd: 接收端套接字描述符

buff: 用來存放recv函數接收到的數據的緩沖區

nbytes: 指明buff的長度

flags: 一般置為0

1) recv先等待s的發送緩沖區的數據被協議傳送完畢,如果協議在傳送sock的發送緩沖區中的數據時出現網路錯誤,那麼recv函數返回SOCKET_ERROR

2)
如果套接字sockfd的發送緩沖區中沒有數據或者數據被協議成功發送完畢後,recv先檢查套接字sockfd的接收緩沖區,如果sockfd的接收緩
沖區中沒有數據或者協議正在接收數據,那麼recv就一起等待,直到把數據接收完畢。當協議把數據接收完畢,recv函數就把s的接收緩沖區中的數據
到buff中(注意協議接收到的數據可能大於buff的長度,所以在這種情況下要調用幾次recv函數才能把sockfd的接收緩沖區中的數據
完。recv函數僅僅是數據,真正的接收數據是協議來完成的)

3) recv函數返回其實際的位元組數,如果recv在時出錯,那麼它返回SOCKET_ERROR。如果recv函數在等待協議接收數據時網路中斷了,那麼它返回0。

4) 在unix系統下,如果recv函數在等待協議接收數據時網路斷開了,那麼調用 recv的進程會接收到一個SIGPIPE信號,進程對該信號的默認處理是進程終止。

B. linux下設置recvfrom為非阻塞

可以使用
1 select pselect
2 poll

3可以使用fcntl給文件描述符添加O—UNBLOCK

C. Linux如何清空Socket緩沖區

socket不是這么接收數據的 由於socket是以數據流的形式發送數據,接收方不知道對方一次性發送了多少數據,也能保證對方一次性發送的數據能在同一刻接收到,所以Receive方法是這么工作的: 接受一個byye[]類型的參數作為緩沖區,在經過一定的時間後把接收到的數據填充到這個緩沖區裡面,並且返回實際接收到數據的長度,這個實際接收到的數據長度有可能為0(沒有接收到數據)、大於0小於緩沖區的長度(接收到數據,但是沒有我們預期的多)、等於緩沖區的長度(說明接收到的數據大於等於我們預期的長度)。 每次接收緩沖區都用同一個byte[] byteMessage,並且你沒有檢查接收到的數據長度,所以第一次你接收到的數據是123456,第二次你只接收到了8,但是緩沖區裡面還有23456,所以加起來就是823456了。 socket接收緩沖區的大小有講究,設置大了接收起來慢,因為它要等盡可能多的數據接收到了再返回;設置小了需要重復多次調用接收方法才能把數據接收完,socket有個屬性,標識了系統默認的接收緩沖區大小,可以參考這個! 還有就是用recv讀取,但是由於不知道緩存里有多少數據,如果是阻塞模式,到最後必然等到超時才知道數據已經讀取完畢,這是個問題。 另一個是用fgetc,通過返回判斷是否是feof: whlie (1) { a=fgetc(f);if (feof(f)) break;//… b=fgetc(f);if (feof(f)) break;//…}當然,我不知道讀取完畢後最後一次調用fgetc會不會堵塞,需要測試。 在非阻塞模式下,我們用recv就可以輕松搞定了,但是阻塞模式下,由於我們不知道緩沖區有多少數據,不能直接調用recv嘗試清除。 使用一個小小的技巧,利用select函數,我們可以輕松搞定這個問題: select函數用於監視一個文件描述符集合,如果集合中的描述符沒有變化,則一直阻塞在這里,直到超時時間到達;在超時時間內,一旦某個描述符觸發了你所關心的事件,select立即返回,通過檢索文件描述符集合處理相應事件;select函數出錯則返回小於零的值,如果有事件觸發,則返回觸發事件的描述符個數;如果超時,返回0,即沒有數據可讀。 重點在於:我們可以用select的超時特性,將超時時間設置為0,通過檢測select的返回值,就可以判斷緩沖是否被清空。通過這個技巧,使一個阻塞的socket成了『非阻塞』socket. 現在就可以得出解決方案了:使用select函數來監視要清空的socket描述符,並把超時時間設置為0,每次讀取一個位元組然後丟棄(或者按照業務需要進行處理,隨你便了),一旦select返回0,說明緩沖區沒數據了(「超時」了)。 struct timeval tmOut;tmOut.tv_sec = 0;tmOut.tv_usec = 0;fd_set fds;FD_ZEROS(&fds);FD_SET(skt, &fds); int nRet; char tmp[2]; memset(tmp, 0, sizeof(tmp)); while(1) { nRet= select(FD_SETSIZE, &fds, NULL, NULL, &tmOut);if(nRet== 0) break;recv(skt, tmp, 1,0);} 這種方式的好處是,不再需要用recv、recvfrom等阻塞函數直接去讀取,而是使用select,利用其超時特性檢測緩沖區是否為空來判斷是否有數據,有數據時才調用recv進行清除。 有人說同樣可以用recv和socket的超時設置去清空啊,這個沒錯,但是你需要直接對socket描述符設置超時時間,而為了清空數據而直接修改socket描述符的屬性,可能會影響到其他地方的使用,造成系統奇奇怪怪的問題,所以,不推薦使用。

D. 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 時使用非阻塞的方式讀取和發送消息,即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); //設置成阻塞模式;
並在接收和發送數據時:
將recv, send 函數的最後有一個flag 參數設置成MSG_DONTWAIT
recv(sockfd, buff, buff_size,MSG_DONTWAIT); //非阻塞模式的消息發送
send(scokfd, buff, buff_size, MSG_DONTWAIT); //非阻塞模式的消息接受

普通文件
對於文件的阻塞模式還是非阻塞模式::
方法1、open時,使用O_NONBLOCK;
方法2、fcntl設置,使用F_SETFL,flags|O_NONBLOCK;

消息隊列
對於消息隊列消息的發送與接受::
//非阻塞 msgsnd(sockfd,msgbuf,msgsize(不包含類型大小),IPC_NOWAIT)
//阻塞 msgrcv(scokfd,msgbuf,msgsize(**),msgtype,IPC_NOWAIT);


阻塞與非阻塞讀的區別: //阻塞和非阻塞的區別在於沒有數據到達的時候是否立刻返回.
讀(read/recv/msgrcv):
讀的本質來說其實不能是讀,在實際中, 具體的接收數據不是由這些調用來進行,是由於系統底層自動完成的。read 也好,recv 也好只負責把數據從底層緩沖 到我們指定的位置.
對於讀來說(read, 或者recv) ::
阻塞情況下::
在阻塞條件下,read/recv/msgrcv的行為::
1、如果沒有發現數據在網路緩沖中會一直等待,
2、當發現有數據的時候會把數據讀到用戶指定的緩沖區,但是如果這個時候讀到的數據量比較少,比參數中指定的長度要小,read 並不會一直等待下去,而是立刻返回。
read 的原則::是數據在不超過指定的長度的時候有多少讀多少,沒有數據就會一直等待。
所以一般情況下::我們讀取數據都需要採用循環讀的方式讀取數據,因為一次read 完畢不能保證讀到我們需要長度的數據,
read 完一次需要判斷讀到的數據長度再決定是否還需要再次讀取。
非阻塞情況下::
在非阻塞的情況下,read 的行為::
1、如果發現沒有數據就直接返回,
2、如果發現有數據那麼也是採用有多少讀多少的進行處理.
所以::read 完一次需要判斷讀到的數據長度再決定是否還需要再次讀取。

對於讀而言:: 阻塞和非阻塞的區別在於沒有數據到達的時候是否立刻返回.
recv 中有一個MSG_WAITALL 的參數::
recv(sockfd, buff, buff_size, MSG_WAITALL),
在正常情況下recv 是會等待直到讀取到buff_size 長度的數據,但是這里的WAITALL 也只是盡量讀全,在有中斷的情況下recv 還是可能會被打斷,造成沒有讀完指定的buff_size的長度。
所以即使是採用recv + WAITALL 參數還是要考慮是否需要循環讀取的問題,在實驗中對於多數情況下recv (使用了MSG_WAITALL)還是可以讀完buff_size,
所以相應的性能會比直接read 進行循環讀要好一些。

注意:: //使用MSG_WAITALL時,sockfd必須處於阻塞模式下,否則不起作用。
//所以MSG_WAITALL不能和MSG_NONBLOCK同時使用。
要注意的是使用MSG_WAITALL的時候,sockfd 必須是處於阻塞模式下,否則WAITALL不能起作用。



阻塞與非阻塞寫的區別: //
寫(send/write/msgsnd)::
寫的本質也不是進行發送操作,而是把用戶態的數據 到系統底層去,然後再由系統進行發送操作,send,write返回成功,只表示數據已經 到底層緩沖,而不表示數據已經發出,更不能表示對方埠已經接收到數據.
對於write(或者send)而言,
阻塞情況下:: //阻塞情況下,write會將數據發送完。(不過可能被中斷)
在阻塞的情況下,是會一直等待,直到write 完,全部的數據再返回.這點行為上與讀操作有所不同。
原因::
讀,究其原因主要是讀數據的時候我們並不知道對端到底有沒有數據,數據是在什麼時候結束發送的,如果一直等待就可能會造成死循環,所以並沒有去進行這方面的處理;
寫,而對於write, 由於需要寫的長度是已知的,所以可以一直再寫,直到寫完.不過問題是write 是可能被打斷嗎,造成write 一次只write 一部分數據, 所以write 的過程還是需要考慮循環write, 只不過多數情況下一次write 調用就可能成功.

非阻塞寫的情況下:: //
非阻塞寫的情況下,是採用可以寫多少就寫多少的策略.與讀不一樣的地方在於,有多少讀多少是由網路發送的那一端是否有數據傳輸到為標准,但是對於可以寫多少是由本地的網路堵塞情況為標準的,在網路阻塞嚴重的時候,網路層沒有足夠的內存來進行寫操作,這時候就會出現寫不成功的情況,阻塞情況下會盡可能(有可能被中斷)等待到數據全部發送完畢, 對於非阻塞的情況就是一次寫多少算多少,沒有中斷的情況下也還是會出現write 到一部分的情況.

E. 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設置成非阻塞模式。

F. c語言的recv()非阻塞方法怎麼弄哦

需要將recv設置超時,Linux下設置超時如下:

//設置發送超時
struct timeval timeout={3,0};//3s
setsockopt(socket,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(struct timeval));
//設置接收超時
setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(struct timeval));
windows下設置超時如下:

int timeout = 3000; //3s
int ret=setsockopt(sock_fd,SOL_SOCKET,SO_SNDTIMEO,&timeout,sizeof(timeout));
int ret=setsockopt(sock_fd,SOL_SOCKET,SO_RCVTIMEO,&timeout,sizeof(timeout));

G. recvfrom總是返回-1,怎麼獲取錯誤碼(非阻塞)

先確保 addrLen初始化了

H. linux如果錯誤碼是eagain代表什麼

linux下使用write\send發送數據報 EAGAIN : Resource temporarily unavailable 錯

首先是我把套接字設置為非同步的了,然後在使用write發送數據時採取的方式是循環發送大量的數據;由於是非同步的,write\send將要發送的數據提交到發送緩沖區後是立即返回的,並不需要對端確認數據已接收。在這種情況下是很有可能出現發送緩沖區被填滿,導致write\send無法再向緩沖區提交要發送的數據。因此就產生了Resource temporarily unavailable的錯誤,EAGAIN 的意思也很明顯,就是要你再次嘗試。

從字面上來看,是提示再試一次。這個錯誤經常出現在當應用程序進行一些非阻塞(non-blocking)操作(對文件或socket)的時候。例如,以 O_NONBLOCK的標志打開文件/socket/FIFO,如果你連續做read操作而沒有數據可讀。此時程序不會阻塞起來等待數據准備就緒返回,read函數會返回一個錯誤EAGAIN,提示你的應用程序現在沒有數據可讀請稍後再試。
又例如,當一個系統調用(比如fork)因為沒有足夠的資源(比如虛擬內存)而執行失敗,返回EAGAIN提示其再調用一次(也許下次就能成功)。
Linux - 非阻塞socket編程處理EAGAIN錯誤
在linux進行非阻塞的socket接收數據時經常出現Resource temporarily unavailable,errno代碼為11(EAGAIN),這是什麼意思?
這表明你在非阻塞模式下調用了阻塞操作,在該操作沒有完成就返回這個錯誤,這個錯誤不會破壞socket的同步,不用管它,下次循環接著recv就可以。對非阻塞socket而言,EAGAIN不是一種錯誤。在VxWorks和Windows上,EAGAIN的名字叫做EWOULDBLOCK。
另外,如果出現EINTR即errno為4,錯誤描述Interrupted system call,操作也應該繼續。
最後,如果recv的返回值為0,那表明連接已經斷開,我們的接收操作也應該結束。
iReadSizeOnce=read(iOpenCom,RxBuf+iReadSize,1024);
if (iReadSizeOnce != ZERO)
{
if (iReadSizeOnce != EAGAIN)
{
continue;
}
else
{
//stCComApiLog.LogError("讀串口操作錯誤");
return(FUN_ERROR);
}
}
需要解決更多linux問題,詳情請看 http://www.linuxprobe.com/chapter-00.html
望採納

I. 同步與非同步,阻塞與非阻塞的區別,以及select,poll和epoll

非同步的概念和同步相對。
(1)當一個同步調用發出後,調用者要一直等待返回消息(結果)通知後,才能進行後續的執行;

(2)當一個非同步過程調用發出後,調用者不能立刻得到返回消息(結果)。實際處理這個調用的部件在完成後,通過 狀態、通知和回調 來通知調用者。

這里提到執行部件和調用者通過三種途徑返回結果:狀態、通知和回調。使用哪一種通知機制,依賴於執行部件的實現,除非執行部件提供多種選擇,否則不受調用者控制。

(A)阻塞調用是指調用結果返回之前,當前線程會被掛起,一直處於等待消息通知,不能夠執行其他業務

(B)非阻塞調用是指在不能立刻得到結果之前,該函數不會阻塞當前線程,而會立刻返回

場景比喻:
舉個例子,比如我去銀行辦理業務,可能會有兩種方式:

在上面的場景中,如果:
a)如果選擇排隊(同步),且排隊的時候什麼都不幹(線程被掛起,什麼都幹不了),是同步阻塞模型;
b)如果選擇排隊(同步),但是排隊的同時做與辦銀行業務無關的事情,比如抽煙,(線程沒有被掛起,還可以干一些其他的事),是同步非阻塞模型;
c)如果選擇拿個小票,做在位置上等著叫號(通知),但是坐在位置上什麼都不幹(線程被掛起,什麼都幹不了),這是非同步阻塞模型;
d)如果選擇那個小票,坐在位置上等著叫號(通知),但是坐著的同時還打電話談生意(線程沒有被掛起,還可以干其他事情),這是非同步非阻塞模型。

對這四種模型做一個總結:
1:同步阻塞模型,效率最低,即你專心排隊,什麼都不幹。
2:非同步阻塞,效率也非常低,即你拿著號等著被叫(通知),但是坐那什麼都不幹
3:同步非阻塞,效率其實也不高,因為涉及到線程的來回切換。即你在排隊的同時打電話或者抽煙,但是你必須時不時得在隊伍中挪動。程序需要在排隊和打電話這兩種動作之間來回切換,系統開銷可想而知。
4:非同步非阻塞,效率很高,你拿著小票在那坐著等叫號(通知)的同時,打電話談你的生意。

linux下幾個基本概念
1:用戶控制項和內核空間。 現代操作系統都是採用虛擬存儲器,在32位操作系統下,它的定址空間(虛擬存儲空間)為4G(2的32次方)。為了保證用戶進程補鞥呢直接操作內核,保證內核的安全,操作系統將虛擬空間劃分為兩部分,一部分為內核空間,一部分為用戶空間。對linux操作系統而言,將最高的1G位元組空間分給了內核使用,稱為內核空間,將較低的3G位元組的空間劃分為用戶空間。

2:進程切換很耗資源 ,為了控制進程的執行,內核必須有能力掛起正在cpu上運行的進程,並恢復以前掛起的某個進程的執行,這種行為叫進程的切換。每次切換,要保存上一個的上下文環境等等,總之記住進程切換很耗資源。

3:文件描述符 :文件描述符在形式上是一個非負整數。實際上,他是一個索引,指向內核為每個進程所維護的該進程打開文件的記錄表。當程序打開一個文件時,內核就會向進程返回一個非負整數的文件描述符。但是文件描述符一般在unix,linux系統中才講。

緩存IO ,大多數系統的默認IO操作都是緩存IO,在linux的緩存IO機制中,操作系統會將IO的數據緩存在系統的頁緩存(page cache)中,也就是說,數據會先被拷貝到操作系統內核的緩沖區,然後才會從操作系統內核的緩沖區拷貝到應用程序的地址空間。 緩存IO的缺點: 數據在傳輸過程中需要在應用程序和地址空間和內核進行多次數據拷貝操作,這種數據拷貝操作鎖帶來的cpu以及內存消耗是很大的。

LINUX的IO模型
網路IO的本質是socket的讀取。socket在linux系統被抽象為流,故對網路IO的操作可以理解為對流的操作。

對於一次IO訪問,比如以read操作為例, 數據會先被拷貝到操作系統內核的緩沖區,然後才會從內核緩沖區拷貝到進程的用戶層,即應用程序的地址空間 。故當一個read操作發生時,其實是經歷了兩個階段:
1:內核緩沖區的數據就位
2:數據從內核緩沖區拷貝到用戶程序地址空間

那麼具體到socket io的一次read操來說,這兩步分別是:
1:等待網路上的數據分組到達,然後復制到內核緩沖區中
2:數據從內核緩沖區拷貝到用戶程序的地址空間(緩沖區)

所以說 網路應用要處理的無非就兩個問題:網路IO和數據計算 ,一般來說網路io帶來的延遲影響比較大。

網路IO的模型大致有如下幾種:

熟悉不? 我們常說的select,poll和epoll就是屬於同步模型中多路復用IO的不同實現方法罷了。 下面分別對同步阻塞,同步不阻塞,同步io復用進行說明。

一:同步阻塞
它是最簡單也最常用的網路IO模型。linux下默認的socket都是blocking的。

從圖中可以看到,用戶進程調用recvfrom這個系統調用後,就處於阻塞狀態。然後kernel就開始了IO的第一個階段:數據准備。等第一個階段准備完成之後,kernel開始第二階段,將數據從內核緩沖區拷貝到用戶程序緩沖區(需要花費一定時間)。然後kernel返回結果(確切的說是recvfrom這個系統調用函數返回結果),用戶進程才結束blocking,重新運行起來。
總結 同步阻塞模型下,用戶程序在kernel執行io的兩個階段都被blocking住了 。但是優點也是因為這個,無延遲能及時返回數據,且程序模型簡單。

二:同步非阻塞
同步非阻塞就是隔一會瞄一下的輪詢方式。同步非阻塞模式其實是可以看做一小段一小段的同步阻塞模式。

三:IO多路復用
由於同步非阻塞方式需要不斷的輪詢,光輪詢就占據了很大一部分過程,且消耗cpu資源。而這個用戶進程可能不止對這個socket的read,可能還有對其他socket的read或者write操作,那人們就想到了一次輪詢的時候,不光只查詢詢一個socket fd,而是在一次輪詢下,查詢多個任務的socket fd的完成狀態,只要有任何一個任務完成,就去處理它。而且,輪詢人不是進程的用戶態,而是有人幫忙就好了。那麼這就是所謂的 IO多路復用 。總所周知的linux下的select,poll和epoll就是這么乾的。。。

selelct調用是內核級別的,selelct輪詢相比較同步非阻塞模式下的輪詢的區別為: 前者可以等待多個socket,能實現同時對多個IO埠的監聽 ,當其中任何一個socket數據准備好了,就返回可讀。 select或poll調用之後,會阻塞進程 ,與blocking IO 阻塞不用在於,此時的select不是等到所有socket數據達到再處理,而是某個socket數據就會返回給用戶進程來處理。
其實select這種相比較同步non-blocking的效果在單個任務的情況下可能還更差一些 ,因為這里調用了select和recvfrom兩個system call,而non-blocking只調用了一個recvfrom,但是 用select的優勢在於它可以同時處理多個socket fd

在io復用模型下,對於每一個socket,一般都設置成non-blocking,但是其實 整個用戶進程是一直被block的 ,只不過用戶process不是被socket IO給block住,而是被select這個函數block住的。

與多進程多線程技術相比,IO多路復用的最大優勢是系統開銷小。

一:select
select函數監視多個socket fs,直到有描述符就緒或者超時,函數返回。當select函數返回後,可以通過遍歷fdset,來找到就緒的描述符。select的基本流程為:

二:poll
poll本質上跟select沒有區別,它將用戶傳入的數組拷貝到內核空間,然後查詢每個fd的狀態,如果某個fd的狀態為就緒,則將此fd加入到等待隊列中並繼續遍歷。如果遍歷完所有的fd後發現沒有就緒的,則掛起當前進程,直到設備就緒或者主動超時。被喚醒後它又要再次遍歷fd。
特點:
1:poll沒有最大連接數限制,因為它是用基於鏈表來存儲的,跟selelct直接監聽fd不一樣。
2:同樣的大量的fd的數組被整體復制與用戶態和內核地址空間之間。
3:poll還有一個特點是水平觸發:如果報告了fd後沒有被處理,則下次poll時還會再次報告該fd。
4:跟select一樣,在poll返回後,還是需要通過遍歷fdset來獲取已經就緒的socket。當fd很多時,效率會線性下降。

三:epoll

epoll支持水平觸發和邊緣觸發,最大的特點在於邊緣觸發,它只告訴進程哪些fd剛剛變為就緒態,並且只會通知一次。還有一個特點是,epoll使用「事件」的就緒通知方式,通過epoll_ctl注冊fd,一旦該fd就緒,內核就會採用類似callback的回調機制來激活該fd,epoll_wait便可以收到通知。

沒有最大並發連接的限制,能打開的FD的上限遠大於1024(1G的內存上能監聽約10萬個埠)。

效率提升,不是輪詢的方式,不會隨著FD數目的增加效率下降。只有活躍可用的FD才會調用callback函數;即Epoll最大的優點就在於它只管你「活躍」的連接,而跟連接總數無關,因此在實際的網路環境中,Epoll的效率就會遠遠高於select和poll。

內存拷貝,利用mmap()文件映射內存加速與內核空間的消息傳遞;即epoll使用mmap減少復制開銷。

聊聊同步、非同步、阻塞與非阻塞
聊聊Linux 五種IO模型
聊聊IO多路復用之select、poll、epoll詳解

閱讀全文

與linuxrecv非阻塞相關的資料

熱點內容
楚天的小說主角 瀏覽:86
重生到民國成為浙江督軍的小說 瀏覽:531
玄幻推母 瀏覽:770
周潤發黃百鳴電影 瀏覽:815
mfc列印pdf 瀏覽:522
大尺度網址 瀏覽:829
飛行中的偶遇電影 瀏覽:983
電影功夫夢演員表 瀏覽:905
128單片機中斷程序編寫 瀏覽:325
休傑克曼脖子上長蛋蛋的電影1002無標題 瀏覽:917
台灣真軍紅羊生日舞會 瀏覽:763
女主叫洛洛的補課小說 瀏覽:34
程序員溝通時笑死 瀏覽:389
易語言網路共享下載源碼 瀏覽:808
誰有那種電影你懂得 瀏覽:195
台灣男同性戀片 瀏覽:71
安卓應用包安裝程序怎麼清除數據 瀏覽:61
催眠合集txt下載 瀏覽:324
韓國車震大尺度電影有哪些 瀏覽:336
割乳酷刑電影 瀏覽:235