为什么在接收到所有数据之前 recv 不会阻塞? [英] Why doesn't recv block until it receives all of the data?

查看:64
本文介绍了为什么在接收到所有数据之前 recv 不会阻塞?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么 recv 系统调用不会阻塞直到接收到所有数据?每次我看到 recv 调用时,它都在一个 while 循环中,它一直在调用 recv 直到所有数据都在那里.为什么不首先使用 recv 块?

Why doesn't the recv system call just block until all the data is received? Every time I have seen a recv call, it's in a while loop which just keeps on calling recv until all the data is there. Why not just have recv block in the first place?

推荐答案

您可以使用 MSG_WAITALL 标志请求 recv 块,直到收到所有数据.但是,如果信号到达,已经执行了一些工作(即接收部分数据)的系统调用不能自动重新启动以接收其余部分.因此,即使使用 MSG_WAITALL,在某些情况下 recv 调用可能会在缓冲区已满之前返回,您必须准备好处理这些情况.鉴于此,许多人只是选择循环,而不会为诸如 MSG_WAITALL 之类的鲜为人知的标志而烦恼.

You can request that recv block until all data is received, with the MSG_WAITALL flag. However, if a signal arrives, a system call that has performed some work (ie, receiving part of the data) cannot be automatically restarted to receive the rest. As such, even with MSG_WAITALL, there are cases where the recv call may return before the buffer is full, and you must be prepared to handle these cases. Given this, many people simply choose to loop and not bother with little-known flags such as MSG_WAITALL.

至于默认情况下为什么会出现这种情况,我想到了几个原因:

As for why this is the case by default, there are a few reasons that come to mind:

  • 您经常希望接收部分读取.例如,如果您在数据传入时以增量方式显示数据,或者如果您将其代理到其他地方,或者如果数据太大,您无法一次在内存中缓冲整个内容.毕竟,如果您只是立即写入文件,您是否关心将它分成 200 次写入而不是 150 次写入?
  • 有时您甚至不知道一开始需要多少数据.考虑一下 telnet 协议,该协议在 BSD 套接字 API 设计时很流行.您通常一次接收少量字节,没有长度字段告诉您预期有多少数据,而且您需要立即显示该数据.在填充缓冲区之前阻塞是没有意义的.同样,对于面向行的协议,例如 SMTP 或 IMAP - 在您收到所有命令之前,您不知道该命令有多长.
  • recv 通常用于数据报套接字,它接收单个数据报,即使它比提供的缓冲区小得多.流式套接字的自然扩展是尽可能多地返回而无需等待.
  • Frequently you want to receive partial reads. For example, if you're incrementally displaying the data as it comes in, or if you're proxying it to somewhere else, or if the data is just so large you can't buffer the whole thing in memory at once. After all, if you're just immediately writing to a file, do you care that you split it across 200 writes instead of, say, 150?
  • Sometimes you don't even know how much data you need at the start. Consider the telnet protocol, which was popular around the time when the BSD sockets API was designed. You'll typically be receiving a handful of bytes at a time, there are no length fields telling you how much data to expect, and moreover you need to display that data right away. It doesn't make sense to block until you fill a buffer here. Likewise with line-oriented protocols such as SMTP or IMAP - you don't know how long the command is until you've received all of it.
  • recv is often used for datagram sockets, where it receives a single datagram, even if it's much smaller than the buffer provided. The natural extension to streaming sockets is to just return as much as you can without waiting.

但最重要的是,由于您需要准备好处理部分缓冲区无论如何,最好强制人们默认处理它,以便他们尽早发现循环中的错误- 而不是让他们一直躲藏起来,直到信号在不幸的时刻到来.

But most importantly, since you need to be prepared to deal with a partial buffer anyway, it's good to force people to deal with it by default, so they turn up the bugs in their loop early - rather than having them remain hiding until a signal arrives at an unfortunate moment.

这篇关于为什么在接收到所有数据之前 recv 不会阻塞?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆