关于非阻塞的recv的时候返回的处理
注意recv()如果讀到數(shù)據(jù)為0,那么就表示文件結(jié)束了,如果在讀的過程中遇到了中斷那么會返回-1,同時置errno為EINTR。
因此判斷recv的條件:
????如果read返回<=0
???????如果==0
???????????表示文件結(jié)束,?處理
???????如果<0?&&?errno==EINTR
???????????表示中斷,處理
???????否則,出錯
我們舉個例子:
int?safe_tcp_recv (int sockfd, void *buf, int bufsize)
{
int cur_len;
recv_again:
cur_len = recv (sockfd, buf, bufsize, 0);
//closed by client
if (cur_len == 0)
{
TRACE_LOG ("connection closed by peer, fd=%d", sockfd);
return 0;
}
else if (cur_len == -1)
{
if (errno == EINTR)
goto recv_again;
else
ERROR_LOG ("recv error, fd=%d, errno=%d %m", sockfd, errno);
}
return cur_len;
}
或者
int?safe_tcp_recv_n (int sockfd, void *buf, int total)
{
int recv_bytes, cur_len;
for (recv_bytes = 0; recv_bytes < total; recv_bytes += cur_len)
{
cur_len = recv (sockfd, buf + recv_bytes, total - recv_bytes, 0);
//closed by client
if (cur_len == 0) //正常關(guān)閉
{
TRACE_LOG ("connection closed by peer, fd=%d", sockfd);
return -1;
}
else if (cur_len == -1)
{
if (errno == EINTR)//還需要在讀
cur_len = 0;
else if (errno == EAGAIN)
{
TRACE_LOG ("recv %d bytes from fd=%d", recv_bytes, sockfd);
return recv_bytes;
}
else
{
ERROR_RETURN (("recv tcp packet error, fd=%d, %m", sockfd), -1);
}
}
}
return recv_bytes;
}
但是write()如果寫入的數(shù)據(jù)為0,那么就表示出錯,也就是無法寫入了,而如果在寫的過程中遇到了中斷,那么write()會返回-1,同時置errno為EINTR。
?因此判斷write是否成功時,條件是write返回的結(jié)果是否<=0
?
int?safe_tcp_send_n (int sockfd, const void *buf, int total)
{
int send_bytes, cur_len;
for (send_bytes = 0; send_bytes < total; send_bytes += cur_len)
{
cur_len = send (sockfd, buf + send_bytes, total - send_bytes, 0);
//closed by client
if (cur_len == 0)
{
TRACE_LOG ("send tcp packet error, fd=%d, %m", sockfd);
return -1;
}
else if (cur_len == -1)
{
if (errno == EINTR)
cur_len = 0;
else if (errno == EAGAIN)
{
return send_bytes;
}
else
{
TRACE_LOG ("send tcp packet error, fd=%d, %m", sockfd);
return -1;
}
}
}
//TRACE_LOG ("send: fd=%d, len=%d", sockfd, send_bytes);
return send_bytes;
}
首先我們看看recv的返回值:
?EAGAIN、EWOULDBLOCK、EINTR與非阻塞 長連接
EINTR指操作被中斷喚醒,需要重新讀/寫
在Linux環(huán)境下開發(fā)經(jīng)常會碰到很多錯誤(設(shè)置errno),其中EAGAIN是其中比較常見的一個錯誤(比如用在非阻塞操作中)。
從字面上來看,是提示再試一次。這個錯誤經(jīng)常出現(xiàn)在當應(yīng)用程序進行一些非阻塞(non-blocking)操作(對文件或socket)的時候。例如,以 O_NONBLOCK的標志打開文件/socket/FIFO,如果你連續(xù)做read操作而沒有數(shù)據(jù)可讀。此時程序不會阻塞起來等待數(shù)據(jù)準備就緒返 回,read函數(shù)會返回一個錯誤EAGAIN,提示你的應(yīng)用程序現(xiàn)在沒有數(shù)據(jù)可讀請稍后再試。重新讀數(shù)據(jù),其實這個也就是說明了一點,網(wǎng)絡(luò)報還沒有發(fā)完結(jié)束呢,還需要繼續(xù)讀,除非返回的是大于0的值,就代表的是讀完了,返回正常讀到的網(wǎng)絡(luò)報的長度。
又例如,當一個系統(tǒng)調(diào)用(比如fork)因為沒有足夠的資源(比如虛擬內(nèi)存)而執(zhí)行失敗,返回EAGAIN提示其再調(diào)用一次(也許下次就能成功)。
Linux - 非阻塞socket編程處理EAGAIN錯誤
在linux進行非阻塞的socket接收數(shù)據(jù)時經(jīng)常出現(xiàn)Resource temporarily unavailable,errno代碼為11(EAGAIN),這是什么意思?
這表明你在非阻塞模式下調(diào)用了阻塞操作,在該操作沒有完成就返回這個錯誤,這個錯誤不會破壞socket的同步,不用管它,下次循環(huán)接著recv就可以。 對非阻塞socket而言,EAGAIN不是一種錯誤。在VxWorks和Windows上,EAGAIN的名字叫做EWOULDBLOCK。
另外,如果出現(xiàn)EINTR即errno為4,錯誤描述Interrupted system call,操作也應(yīng)該繼續(xù)。
最后,如果recv的返回值為0,那表明連接已經(jīng)斷開,我們的接收操作也應(yīng)該結(jié)
總結(jié)
以上是生活随笔為你收集整理的关于非阻塞的recv的时候返回的处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 成都欢乐谷入园须知
- 下一篇: 天命奇御二出生天赋怎么选