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

recvlinux非阻塞

發布時間:2022-08-22 16:02:31

『壹』 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信號,進程對該信號的默認處理是進程終止。

『貳』 linux支持非同步的非阻塞的fsync嗎

一、概念
非同步:某個事情需要10s完成。而我只需要調用某個函數告訴xxx來幫我做(然後我再干其他的事情)
同步:某個事情需要10s完成,我需要一直等它完成(等10s),再能繼續後面的工作。
阻塞:做某件事情,直到完成,除非超時
非阻塞:嘗試做,如果不能做,就不做(直接返回),如果能做,就做。

前兩者和後兩者不容易區分,不過前兩者更多的有涉及到多線程交互(消息)的場景。

二、舉個例子

小李喝了想喝水,於是去煮開水。
1、小李把水壺放到爐子上,等待水燒開。(同步阻塞)
小李感覺這樣太費時間。
2、小李把水壺放到爐子上,去客廳看電視,時不時去廚房看看水開沒有。(同步非阻塞)
小李還是覺得自己這樣太累,於是買了把會響笛的那種水壺。水開之後,能發出聲音。
3、小李把響水壺放到爐子上,等待水壺發出聲音。(非同步阻塞)
覺得這樣傻等意義不大
5、小李把響水壺放到爐子上,去客廳看電視,水壺響之前不再去看它了,響了再去拿壺。(非同步非阻塞)
這樣真好。

三、深入理解

阻塞就是 recv/read的時候 socket接收緩沖區要是有數據就讀, 沒數據我就一直睡覺賴著不走,直到有數據來了讀完我才走。send/write的時候,要是發送緩沖區滿了,沒有空間繼續發送了我也一直睡覺賴著不走,直到發送緩沖區騰出足夠的空間讓我把數據全部塞到發送緩沖區里我才走。(當然如果你通過setsockopt設置了讀寫超時,超時時間到了還是會返回-1和EAGAIN,不再睡覺等待)
非阻塞就是recv/read的時候,要是接收緩沖區有數據我就讀完,沒有數據我直接帶著返回的-1和EGAIN走人,絕不睡覺等待耽誤時間。write/send的時候, 要是發送緩沖區有足夠的空間,就立刻把數據塞到發送緩沖區去,然後走人,如果發送緩存區滿了,空間不足,那直接帶著返回的-1和EAGAIN走人。

至於IO多路復用,首先要理解的是,操作系統為你提供了一個功能,當你的某個socket接收緩存區有數據可讀,或者發送緩沖區有空間可寫的時候,它可以給你一個通知。這樣當配合非阻塞的socket使用時,只有當系統通知我哪個描述符可讀了,我才去執行read操作,可以保證每次read都能讀到有效數據而不做純返回-1和EAGAIN的無用功。寫操作類似。操作系統的這個功能通過select/poll/epoll之類的系統調用函數來使用,這些函數都可以同時監視多個描述符的讀寫就緒狀況,這樣,多個描述符的I/O操作都能在一個線程內完成,這就叫I/O多路復用,這里的「復用」指的是復用同一個線程。

至於事件驅動,其實是I/O多路復用的一個另外的稱呼。

『叄』 linux 下調用recv函數,死循環在recv函數裡面,什麼原因

建議你用strace看那幾個線程確切是卡在哪裡

而且你描述的是,死循環。 recv函數怎麼會死循環?

還有,當你的系統壓力變大的時候, 會出現epoll提示某socket可用,但是等你去讀的時候該socket已經被關閉的情況,你看看這種情況會不會對你的程序造成影響。
----------------------------
man recv
RETURN VALUE
These calls return the number of bytes received, or -1 if an error occurred. The return value will be 0 when the peer has performed an
orderly shutdown.

你可以看到,當對端關閉socket的時候recv返回值是0。 那麼作為你的程序,你又沒有判斷這種情況呢? 你默認的如果是使用EPOLLET模式, 你肯定不停的讀socket直到EAGAIN出現,但是如果返回值0的話,並不會出現EAGAIN。

建議你還是多用strace來查詢問題所在,有時候比gdb更能直接找出原因。

還有再糾正一點,recv是一個linux系統調用,要麼是阻塞要麼是返回,不存在死循環的問題的, 死循環肯定是出在你的程序代碼中。 如果你覺得recv本身不退出又佔用大量cpu,那就是linux庫出bug或者是內核bug了。

『肆』 linux下設置recvfrom為非阻塞

可以使用
1 select pselect
2 poll

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

『伍』 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設置成非阻塞模式。

『陸』 C++ Socket如何設置Accept和Recv的非阻塞

void*CTCPClient::AUReceive(void*aInstance)
{
structtimevaltv_out;
CTCPClient*pInstance=(CTCPClient*)aInstance;
fd_setsockfd;
pInstance->m_IsExit=false;
charReceiveDataInfo[1024]={0};

charTemp[4]={0};

while(pInstance->m_IsExit==false)
{
if(pInstance->m_socket==SOCKETERROR)
{
FD_ZERO(&sockfd);
}
else
{
FD_ZERO(&sockfd);
FD_SET(pInstance->m_socket,&sockfd);
}
fd_setmySet=sockfd;
memset(ReceiveDataInfo,0,1024);
intMax_ID=pInstance->m_socket;
intposition=0;
tv_out.tv_sec=0;
tv_out.tv_usec=1000;
if(select(Max_ID+1,&mySet,NULL,NULL,&tv_out)>0)//主要這一句
{
longnBytesRead=0;

unsignedlongnBytesToRecv=pInstance->mreceivebuflen-pInstance->hasrecvlen;
pInstance->recvsignal.Wait();
if(pInstance->m_socket==SOCKETERROR)
{
FD_ZERO(&sockfd);
pInstance->recvsignal.Release();
continue;
}
nBytesRead=recv(pInstance->m_socket,(char*)pInstance->mreceivebuf+pInstance->hasrecvlen,nBytesToRecv,0);
pInstance->recvsignal.Release();
if(nBytesRead==-1||nBytesRead==0)
{
pInstance->m_CSocket.SocketClose(pInstance->m_socket);
FD_ZERO(&sockfd);
pInstance->m_socket=SOCKETERROR;
continue;
}
pInstance->hasrecvlen+=nBytesRead;
pInstance->m_CLog->ddprintf("CTCPClient","AUReceive",1,"recvapackage!");
pInstance->m_CLog->ddprintf("CTCPClient","AUReceive",1,"recvlenis%ld",nBytesRead);
if((pInstance->FindCompletePackage(pInstance->receive,nBytesRead,pInstance->mreceivebuf))==false)
{
continue;
}
//printf("validlenis%d ",pInstance->validlen);
pInstance->hasrecvlen=0;
if(pInstance->validlen<8)
{
pInstance->m_CLog->ddprintf("CTCPClient","AUReceive",1,"receivedataiserror(leniserror)!");
continue;
}
for(inti=0;i<pInstance->validlen;i++)
{
sprintf(Temp,"%2x-",pInstance->receive[i]);
strcat(ReceiveDataInfo,Temp);
}
pInstance->m_CLog->ddprintf("CTCPClient","AUReceive",1,"recvdatais:%s",ReceiveDataInfo);
unsignedintrecvSN=Char2Int(pInstance->receive);
position+=4;

unsignedintrecvCMD=Char2Short(pInstance->receive+position);
position+=2;

unsignedlongbuflen=Char2Short(pInstance->receive+position);
position+=2;

if(pInstance->validlen-position!=buflen)
{
pInstance->m_CLog->ddprintf("CTCPClient","AUReceive",1,"receivedataiserror(lenerror)!");
continue;
}

stCommandnewReceiveCommand;
newReceiveCommand.CmdSN=recvSN;
//newReceiveCommand.DataBuffer="";


boolrest=pInstance->FindSentCommand(newReceiveCommand);
if(rest==false)
{
pInstance->m_CLog->ddprintf("CTCPClient","AUReceive",1,"receivedataiserror(SNcannotfind)!");
continue;
}
if(newReceiveCommand.CmdCode!=recvCMD)
{
pInstance->m_CLog->ddprintf("CTCPClient","AUReceive",1,"receivedataiserror(CMDiserror)!");
continue;
}

char*RecvData=newchar[buflen];
memcpy(RecvData,pInstance->receive+position,buflen);
pInstance->UpdateSentCommand(recvSN,buflen,RecvData);

newReceiveCommand.WaitEvent->Release();
pInstance->m_CLog->ddprintf("CTCPClient","AUReceive",1,"sendasignalofrecv!");
delete[]RecvData;
}
else
Csleep(100);

}
//pInstance->m_ThdRecv.ThreadExit();
returnNULL;
}

這個是recv設置非阻塞的方式,accept也是差不多

『柒』 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 到一部分的情況.

『捌』 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));

閱讀全文

與recvlinux非阻塞相關的資料

熱點內容
變身小說男變女嫁人 瀏覽:34
原罪未刪減床戲在什麼時間 瀏覽:848
最新全裸韓劇倫理片有哪些 瀏覽:294
男主帥的日本粉紅電影 瀏覽:802
重生到香港混黑道小說 瀏覽:501
男作家的妻子出軌孫志 瀏覽:913
男主是鴨子女主是大老闆 瀏覽:564
日批的小說 瀏覽:580
周香允參與過所有的電影 瀏覽:928
紅羊出品有哪些 瀏覽:400
14路末班車電影陳明輝結局 瀏覽:977
金庸小說全集下載 瀏覽:792
美國電影主角和老師偷情 瀏覽:132
成人兩性微電影 瀏覽:408
台灣三級的絕版老電影 瀏覽:161
電影雙男主肉 瀏覽:986
重生之北美建國 瀏覽:129
每天工作4小時的程序員 瀏覽:462
香港學生犯罪電影 瀏覽:869
0855aa 瀏覽:506