调用recv函数时是否需要对接收缓冲区指针做偏移处理?
关于recv两种写法的正确性说明
- 首先可以明确给出结论:你担心的问题确实存在,你看到的第二种
recv写法是错误的,你的写法则是符合「累计接收满指定长度数据存入同一缓冲区」需求的正确实现。
两种写法的核心差异
recv函数的第二个参数是内核写入接收数据的内存起始地址,第三个参数是本次调用允许写入的最大字节数:
- 你的写法每次传入
buf + n作为起始地址:新接收的数据会从已有数据的末尾开始写入,同时第三个参数传入剩余可用长度len - n避免缓冲区溢出,完全符合累计接收的逻辑,只要加上错误判断就可以正常使用。 - 你看到的第二种写法每次都传入
buf作为起始地址:后续recv调用返回的数据会直接从缓冲区头部开始覆盖之前的内容,累加的n只是统计了总共收到的字节数,但缓冲区里只会保留最后一次调用recv收到的数据,前面的内容全部丢失,完全无法实现「收满len字节存在buf里」的需求。
为什么会有大量错误示例流传?
很多示例把两种不同的使用场景搞混了:
如果业务不需要把所有接收的数据攒在同一个缓冲区,而是每次收到数据就立即处理(比如即时打印、写入文件、转发到其他套接字),正确的写法应该是这样的,和你看到的错误写法有本质区别:
char buf[1000]; int n; // 这里不会累加n,也不会用n < len作为循环条件 while((n = recv(socket, buf, sizeof(buf), 0)) > 0) { // 立即处理本次收到的n个字节,处理完后buf的内容就不需要保留了 fwrite(buf, 1, n, output_fp); }
很多不负责任的教程抄代码的时候漏了处理逻辑,又错误加上了n += recv和n < len的循环条件,才产出了你看到的错误示例。
你的写法的优化建议
目前你的写法缺少异常处理逻辑,建议补充recv返回值的判断:
- 返回-1:表示发生了系统错误,需要根据
errno判断是临时中断还是致命错误,直接跳出循环做错误处理 - 返回0:表示对端已经正常关闭了连接,此时不可能再收到剩余的数据,直接跳出循环处理半开连接的情况
内容的提问来源于stack exchange,提问作者Arthur A.
相关产品推荐
相关产品推荐

