本文中分析的都是非阻塞態的socket錯誤代碼,因爲阻塞態也不會出現EWOULDBLOCK錯誤。
1、recv函數:
返回值<0時並且(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)的情況下認爲連接是正常的,繼續接收。
當socket設置爲非阻塞的時候,recv返回錯誤時纔會有 errno == EWOULDBLOCK || errno == EAGAIN兩種情況;
- #define EWOULDBLOCK EAGAIN
因爲宏定義EWOULDBLOCK和 EAGAIN ,所以二者等價;
- EWOULDBLOCK,WOULD英文語法是表示過去將來式,表示本來應該。。。;
放在此處的意思是,本來應該阻塞,卻沒有阻塞。(也就是並沒有發生阻塞,原因是設置了非阻塞態,也就說這個錯誤是在非阻塞態時纔會有的)
EWOULDBLOCK的意思是如果你不把socket設成非阻塞(即阻塞)模式時,這個讀操作將阻塞,也就是說數據還未準備好(但系統知道數據來了,所以select告訴你那個socket可讀)。使用非阻塞模式做I/O操作的細心的人會檢查errno是不是EAGAIN、EWOULDBLOCK、EINTR,如果是就應該重讀,一般是用循環。如果你不是一定要用非阻塞就不要設成這樣,這就是爲什麼系統的默認模式是阻塞。
int foo(SOCKET socket, char *buff, int length)
{
int nleft, nread;
nleft = length;
while(nleft > 0)
{
nread = recv(socket, buff, nleft,0);
if(nread == 0)//對端socket調用close()關閉
{
printf("%s", strerror(errno));
return -1;
}
if(nread < 0)
{
if(errno == EINTR ||errno == EAGAIN ||errno == EWOULDBLOCK)
continue;
printf("%s", strerror(errno));
return -1;
}
nleft -= nread;
buff += nread;
}
return(length - nleft);
}
如示例,recv函數是不能通過返回值來判斷讀滿了buff個數據的,因爲recv返回0表示,對端socket正常關閉了。
所以,需要通過判斷未讀的字節數>0?來解決這個問題。
2、send函數
int foo(SOCKET socket, char *buff, int length)
{
int nleft, nsend;
nleft = length;
while(nleft > 0)
{
nsend = send(socket, buff, nleft,0);
if(nsend == 0)//對端socket調用close()關閉
{
printf("%s", strerror(errno));
return -1;
}
if(nsend < 0)
{
if(errno == EINTR ||errno == EAGAIN ||errno == EWOULDBLOCK)
continue;
printf("%s", strerror(errno));
return -1;
}
nleft -= nsend;
buff += nsend;
}
return(length - nleft);
}
3、附錄
recv函數errno值
send函數errno值