非阻塞模式下 SEND 和 RECV 函数的返回值总结

您所在的位置:网站首页 返回值为1返回值为0 非阻塞模式下 SEND 和 RECV 函数的返回值总结

非阻塞模式下 SEND 和 RECV 函数的返回值总结

2024-03-22 23:13| 来源: 网络整理| 查看: 265

 send 和 recv 函数的各种返回值意义:

返回值 n返回值含义大于 0成功发送 n 个字节0对端关闭连接小于 0( -1)出错或者被信号中断或者对端 TCP 窗口太小数据发不出去(send)或者当前网卡缓冲区已无数据可收(recv)

我们来逐一介绍下这三种情况:

返回值大于 0

对于 send 和 recv 函数返回值大于 0,表示发送或接收多少字节,需要注意的是,在这种情形下,我们一定要判断下 send 函数的返回值是不是我们期望发送的缓冲区长度,而不是简单判断其返回值大于 0。举个例子:

1 2 3 4 5 int n = send(socket, buf, buf_length, 0); if (n > 0) { printf("send data successfully\n"); }

很多新手会写出上述代码,虽然返回值 n 大于 0,但是实际情形下,由于对端的 TCP 窗口可能因为缺少一部分字节就满了,所以返回值 n 的值可能在 (0, buf_length] 之间,当 0 < n < buf_length 时,虽然此时 send 函数是调用成功了,但是业务上并不算正确,因为有部分数据并没发出去。你可能在一次测试中测不出 n 不等于 buf_length 的情况,但是不代表实际中不存在。所以,建议要么认为返回值 n 等于 buf_length 才认为正确,要么在一个循环中调用 send 函数,如果数据一次性发不完,记录偏移量,下一次从偏移量处接着发,直到全部发送完为止。

1 2 3 4 5 6 //不推荐的方式一 int n = send(socket, buf, buf_length, 0); if (n == buf_length) { printf("send data successfully\n"); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 //推荐的方式二:在一个循环里面根据偏移量发送数据 bool SendData(const char* buf, int buf_length) { //已发送的字节数目 int sent_bytes = 0; int ret = 0; while (true) { ret = send(m_hSocket, buf + sent_bytes, buf_length - sent_bytes, 0); if (ret == -1) { if (errno == EWOULDBLOCK) { //严谨的做法,这里如果发不出去,应该缓存尚未发出去的数据,后面介绍 break; } else if (errno == EINTR) continue; else return false; } else if (ret == 0) { return false; } sent_bytes += ret; if (sent_bytes == buf_length) break; //稍稍降低 CPU 的使用率 usleep(1); } return true; }

返回值等于 0

通常情况下,如果 send 或者 recv 函数返回 0,我们就认为对端关闭了连接,我们这端也关闭连接即可,这是实际开发时最常见的处理逻辑。send 函数主动发送 0 字节时也会返回 0,这是一种特例,我们下一节会介绍。

返回值小于 0

对于 send 或者 recv 函数返回值小于 0 的情况(即返回 -1),根据前文的讨论,此时并不表示 send 或者 recv 函数一定调用出错。这里列一个表格说明:

 返回值和错误码send 函数recv 函数操作系统说明1返回 -1,错误码 EWOUDBLOCK 或 EAGAINTCP 窗口太小,数据暂时发不出去当前内核缓冲区中无可读数据Linux2返回 -1,错误码 EINTR被信号中断,需要重试被信号中断,需要重试Linux3返回 -1,错误码不是上述 1 和 2出错出错Linux4返回 -1,错误码 WSAEWOUDBLOCKTCP 窗口太小,数据暂时发不出去当前内核缓冲区中无可读数据Windows5返回 -1,错误码不是上述 4出错出错Windows

注意:这里是针对非阻塞模式下 socket 的 send 和 recv 返回值,如果是阻塞模式下 socket,如果返回值是 -1(Windows 上即 SOCKET_ERROR),则一定表示出错。

阻塞与非阻塞的 SOCKET 的各自适用场景

阻塞的 socket 函数在调用 send、recv、connect、accept 等函数时,如果特定的条件不满足,就会阻塞其调用线程直至超时,非阻塞的 socket 恰恰相反。这并不意味着非阻塞模式的 socket 模式比阻塞模式的 socket 模式好,二者各有优缺点。

非阻塞模式的 socket,一般用于需要支持高并发多 QPS 的场景下(如服务器程序),但是正如前文所述,这种模式让程序执行流和控制逻辑变复杂;相反,阻塞模式逻辑简单,程序结构简单明了,常用于一些特殊的场景。这里举两个应用的场景:

示例一

程序需要临时发送一个文件,文件分段发送,每段对端都会的给与一个应答,程序可以单独开一个任务线程,在这个任务线程函数里面,使用先 send 后 recv 再 send 再 recv 的模式,每次 send 和 recv 都是阻塞式的。

示例二

A 端与 B 端之间只有问答模式,即 A 发送给 B 一个请求,B 必定会应答给 A 一个响应,除此以外,B 不会给 A 推送任何数据,也可以采取阻塞模式,每次 send 完请求后,就可以直接使用阻塞式的 recv 去接受一定要有的应答包。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3