非阻塞模式下,send和recv返回值的各种处理
返回值
返回值n | 返回值含义 |
---|---|
大于0 | 成功发送或接收n个字节 |
等于0 | 对端关闭连接 |
小于0 | errno 为EINTR、EAGAIN、EWOULDBLOCK正常,可以继续发送或接收,其他errno则为异常,需要关闭close(fd) |
场景处理
返回值大于0
send/recv write/read 函数返回值大于 0,表示成功发送或成功接收了多少字节,但是发送或者接收的字节数可能是部分字节数,比如你需要发送buf_length长度的数据,但是send/write返回的n有可能 < buf_length,这是因为发送缓冲区可能已经满了。这个时候需要注意处理这种场景,监听poll_out事件,再次触发发送,只有(n == buf_length)才算发送成功。
返回值等于0
send/recv write/read 函数返回 0,则是对端关闭了连接。
这里有一种特殊场景,就是发送端在调用send/write的时候就是填了0,即发了0字节。这种场景下底层协议栈并不会将0字节发送出去,也就是调send/write的时候避免出现此场景。
返回值小于0
不同errno的处理
返回值小于0,需要区分errno。
- errno为EINTR、EAGAIN、EWOULDBLOCK这三个错误码,在非阻塞模式下属于正常,可以循环发送/接收,或者等待poll_in/poll_out事件触发,继续发送/接收。
- errno为其他错误码,则需要关闭连接。
EINTR、EAGAIN、EWOULDBLOCK的产生原因
-
EINTR:当进程在一个慢系统调用中阻塞时,如果捕获到某个信号且相应信号处理函数返回时,这个系统调用不再阻塞而是被中断,就会调用返回错误(一般为-1)并设置 errno 为 EINTR。
-
EAGAIN:在非阻塞 I/O 操作中,如果由于资源限制或不满足条件导致操作无法立即完成,系统调用会返回 EAGAIN。例如,在非阻塞模式下,如果连续进行 read 操作而没有数据可读,或者在 send 函数中的 size 变量大小超过了 tcp_sendspace 的值,此时程序不会阻塞起来等待数据准备就绪返回,而是立即返回 -1,并设置 errno 为 EAGAIN。
-
EWOULDBLOCK:在某些套接字的函数操作不能立即完成时,会出现错误码 EWOULDBLOCK。实际上,在许多系统中,EAGAIN 和 EWOULDBLOCK 是同一个错误码。这表明你在非阻塞模式下调用了阻塞操作,在该操作没有完成就返回这个错误。