因此判斷recv的條件:
????如果read返回<=0
???????如果==0
???????????表示文件結束,?處理
???????如果<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) //正常關閉
{
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()如果寫入的數據為0,那么就表示出錯,也就是無法寫入了,而如果在寫的過程中遇到了中斷,那么write()會返回-1,同時置errno為EINTR。
?因此判斷write是否成功時,條件是write返回的結果是否<=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環境下開發經常會碰到很多錯誤(設置errno),其中EAGAIN是其中比較常見的一個錯誤(比如用在非阻塞操作中)。
從字面上來看,是提示再試一次。這個錯誤經常出現在當應用程序進行一些非阻塞(non-blocking)操作(對文件或socket)的時候。例如,以 O_NONBLOCK的標志打開文件/socket/FIFO,如果你連續做read操作而沒有數據可讀。此時程序不會阻塞起來等待數據準備就緒返 回,read函數會返回一個錯誤EAGAIN,提示你的應用程序現在沒有數據可讀請稍后再試。重新讀數據,其實這個也就是說明了一點,網絡報還沒有發完結束呢,還需要繼續讀,除非返回的是大于0的值,就代表的是讀完了,返回正常讀到的網絡報的長度。
又例如,當一個系統調用(比如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,那表明連接已經斷開,我們的接收操作也應該結