本文中分析的都是非阻塞态的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,如果是就应该重读,一般是用循环。如果你不是一定要用非阻塞就不要设成这样,这就是为什么系统的默认模式是阻塞。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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值