您的位置:首页 > 科技 > IT业 > 成品网站源码下载_公司域名一年多少费用_百度竞价入门教程_百度企业号

成品网站源码下载_公司域名一年多少费用_百度竞价入门教程_百度企业号

2025/4/19 10:07:20 来源:https://blog.csdn.net/djb100316878/article/details/147034713  浏览:    关键词:成品网站源码下载_公司域名一年多少费用_百度竞价入门教程_百度企业号
成品网站源码下载_公司域名一年多少费用_百度竞价入门教程_百度企业号

在 C/C++网络编程中,尤其是在处理 TCP 套接字时,recv函数扮演着基石般的角色。它是从连接对端读取传入数据的主要机制。

recv 函数原型

我们先从标准的 POSIX 函数原型开始:

#include <sys/socket.h>ssize_t recv(int sockfd, void *buf, size_t len, int flags);

sockfd: 接收数据的套接字文件描述符。

buf: 指向用于存储接收数据的缓冲区的指针。

lenbuf缓冲区的最大长度,即本次调用最多接收的字节数。

flags: 控制接收操作的标志位(例如 MSG_PEEKMSG_WAITALL)。通常设为 0 表示标准行为。

返回值 ssize_t 类型对于理解调用的结果至关重要。

解读 recv 返回值

recv 函数的返回值主要有以下三种情况:

返回值 > 0: 成功接收数据
含义: 调用成功,并从对端接收到了数据。
: 返回值表示实际接收到并放入buf中的字节数。
注意: 这个值可能小于你请求的 len,即使发送方发送了更多的数据。这是正常现象,原因包括网络缓冲区大小、TCP 分段、以及调用时套接字接收缓冲区中实际可用的数据量等。

处理: 处理接收到的 返回值 这么多字节的数据。如果你的应用层协议期望更多的数据,你可能需要在一个循环中再次调用 recv,直到接收到完整的消息或发生错误/连接关闭。

返回值 == 0: 对端已正常关闭连接

含义: 远端对等方(peer)已经执行了有序关闭(graceful shutdown)序列(发送了 FIN 包),表示它不会再发送任何数据了。
0
注意: 这不是一个错误。这是一个信号,表明连接的读取方向已经由对端关闭。你无法再从此连接接收到任何数据。

处理: 识别到连接正在关闭。通常应停止尝试接收数据,可能需要关闭你自己的写端(如果还没关闭,使用 shutdown(sockfd, SHUT_WR)),并最终调用 close(sockfd) 来释放套接字资源。

返回值 == -1: 发生错误

含义recv 调用失败。
-1

处理: 这是错误处理的关键所在,不同的值处理方式是不一样的。

错误处理:哪些 errno 值是“可接受”的?

recv 返回 -1 时,并非所有的 errno 值都意味着连接已死或必须立即放弃。有些错误指示的是临时状态或需要特定处理逻辑的情况,而不是直接终止连接。这些就是在面试题里面说的“可接受”的错误。

“可接受” / 非致命错误: EAGAINEWOULDBLOCK: (这两个宏通常具有相同的值)

场景: 主要发生在套接字被设置为非阻塞模式 (O_NONBLOCK) 时。

含义: 当前套接字的接收缓冲区中没有数据可读,并且在不阻塞的情况下无法立即完成读取操作。这不是一个真正的错误,而是对套接字状态的一种描述。

处理: 不要关闭连接。这是非阻塞 I/O 中的预期行为。标准的处理方式是使用 I/O 多路复用机制(如 epollselectpoll)。这些机制会通知你套接字何时变为可读状态,届时你再安全地重试 recv 调用。在一个紧密循环中反复调用 recv 而不等待(忙等待)是非常低效的。

// 概念性的非阻塞循环(结合epoll/select)
while (true) {// 使用epoll_wait, select等等待sockfd变为可读// ... 等待逻辑 ...ssize_t bytes_received = recv(sockfd, buffer, sizeof(buffer), 0);if (bytes_received > 0) {// 处理数据...} else if (bytes_received == 0) {// 对端关闭连接handle_close(sockfd);break;} else { // bytes_received == -1if (errno == EAGAIN || errno == EWOULDBLOCK) {// 当前无数据可用,返回继续等待(epoll/select)continue;} else if (errno == EINTR) {// 被信号中断,直接重试continue;} else {// 发生其他错误perror("recv failed"); // 打印错误信息handle_error_close(sockfd); // 处理错误并关闭连接break;}}
}

EINTR:

致命 / 不可恢复错误:

这些错误通常表明连接本身、套接字状态或程序逻辑存在问题。在这些错误发生后继续在该套接字上操作通常是无意义或不可能的。

ECONNRESET: 连接被对端重置。对方发送了 RST(重置)包,很可能是因为对方异常终止或网络问题。连接已失效。

ENOTCONN: 套接字未连接(例如,在 TCP 套接字上调用 connectaccept 之前,或连接已断开后尝试 recv)。

ETIMEDOUT: 连接超时。可能在连接建立阶段发生,或在数据传输过程中由于网络状况极差或设置了 SO_RCVTIMEO 并发生较长超时而发生。通常意味着连接不可用。

ECONNREFUSED: 远程主机主动拒绝连接(更常见于 connect 调用,但在特定的 UDP recvfrom 场景下也可能遇到)。

EBADF: 无效的文件描述符 (sockfd 没有指向一个打开的套接字)。这是程序逻辑错误。

EFAULT: 传入的缓冲区指针 buf 指向了进程地址空间之外的无效内存。这是程序逻辑错误。

EINVAL: 提供了无效的参数(例如,无效的 flags)。程序逻辑错误。

ENOTSOCK: 文件描述符 sockfd 指的不是一个套接字。程序逻辑错误。

对于致命错误的处理: 记录具体的 errno 值和错误信息(使用 perrorstrerror),清理与该连接相关的资源,并调用 close(sockfd) 关闭套接字。

回答

1、区分出 recv 的三种返回值 (>0, 0, -1) 及其含义。

3、知道 -1 需要检查 errno

3、明确指出 EAGAIN/EWOULDBLOCKEINTR 是可接受的、需要特殊处理(等待/重试)的错误,尤其是在非阻塞 I/O 场景下 EAGAIN/EWOULDBLOCK 是正常情况。

对于“什么错误是可接受的?”这个问题,最核心的答案是 EAGAIN (或 EWOULDBLOCK) 和 EINTR

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com