【问题标题】:Does send() always send whole buffer?send() 是否总是发送整个缓冲区?
【发布时间】:2012-09-21 08:17:09
【问题描述】:

send() 应返回发送的字节数或错误代码,但我发现的所有示例仅使用错误代码检查它,而不是发送的字节数。

//typical example
int cnt=send(s,query,strlen(query),0);
if (cnt < 0) return(NULL);
//Hey, what about cnt < strlen(query)?

【问题讨论】:

    标签: c linux sockets


    【解决方案1】:

    问:“send()”是否总是返回整个缓冲区?

    答:不,不一定。

    来自 Beej 的指南: * http://beej.us/guide/bgnet/html/multi/syscalls.html#sendrecv

    send() 返回实际发送的字节数——这可能是 少于您告诉它发送的数量!看,有时你会告诉它 发送一大堆数据,但它无法处理。会火 尽可能多地关闭数据,并相信你会发送其余的 之后。请记住,如果 send() 返回的值与 len 中的值,由您决定发送字符串的其余部分。好的 新闻是这样的:如果数据包很小(小于 1K 左右),它将 可能设法一次性发送整件事。同样,-1 是 出错时返回,并将 errno 设置为错误号。

    问:“recv()”是否总是读取整个缓冲区?

    A:不,绝对不是。您应该永远假设您收到的缓冲区是“整个消息”。或者假设您收到的消息来自一个单个消息。

    这里有一个很好的简短解释。它适用于 Microsoft/C#,但适用于 所有 套接字 I/O,任何语言:

    【讨论】:

    • -1:完全倒退——对于任何基于流的协议(例如 TCP),如果本地缓冲区几乎已满,则发送返回的数量可能少于请求的数量。对于数据报协议(例如 UDP),发送要么失败,要么将整个缓冲区作为数据包发送——不可能进行部分发送。
    • @Kiril Kirov - 你和 Chris Dodd 绝对正确。我的脑袋放屁 - 道歉。我已经更正了我的答案。谢谢!
    • 没问题 :) 现在 +1,引用 Beej 的指南。
    • 更好,但仍然不能说明全部情况——行为实际上取决于套接字的类型,并且 STREAM(tcp) 套接字的行为与 DGRAM(udp) 套接字不同。特别是,UDP 套接字上的发送要么将整个缓冲区作为一个数据包发送,要么失败(如果它太大而无法作为 1 个数据包发送,通常使用 EMSGSIZE);它永远不会返回短发送。
    • @ChrisDodd 请说出阻塞模式 TCP 发送并不总是发送整个缓冲区的实现。
    【解决方案2】:

    不,它没有。

    参考见the man page for send:

    当消息不适合套接字的发送缓冲区时,send() 通常阻塞,除非套接字已被置于非阻塞 I/O 模式。 在非阻塞模式下,它将失败并出现错误 EAGAIN 或 EWOULDBLOCK 案子。 select(2) 调用可用于确定何时可以发送 更多数据。

    【讨论】:

    • 手册页令人困惑:该注释不适用于 SOCK_STREAM 套接字,仅适用于其他类型。
    【解决方案3】:

    答案在man 2 send的另一部分:

       When the message does not fit into  the  send  buffer  of  the  socket,
       send()  normally blocks, unless the socket has been placed in nonblock‐
       ing I/O mode.  In nonblocking mode it would fail with the error  EAGAIN
       or  EWOULDBLOCK in this case.  The select(2) call may be used to deter‐
       mine when it is possible to send more data.
    

    或者,或者,POSIX 版本 (man 3p send):

       If  space is not available at the sending socket to hold the message to
       be transmitted, and the socket file descriptor does not have O_NONBLOCK
       set,  send()  shall  block  until  space is available.  If space is not
       available at the sending socket to hold the message to be  transmitted,
       and  the  socket file descriptor does have O_NONBLOCK set, send() shall
       fail. The select() and poll() functions can be used to  determine  when
       it is possible to send more data.
    

    因此,虽然部分数据的 read 很常见,但阻塞模式下的部分 send 不应该发生(除非实现细节)。

    【讨论】:

    • 手册页令人困惑:注释不适用于 SOCK_STREAM 套接字,仅适用于其他类型
    • Posix 函数定义的另一部分是相关的——“如果消息太长而无法通过底层协议,则 send() 将失败并且不应传输任何数据”,即这就是为什么您不会在 UDP 上获得部分发送。
    猜你喜欢
    • 1970-01-01
    • 2015-07-08
    • 1970-01-01
    • 2011-04-03
    • 1970-01-01
    • 2011-08-02
    • 1970-01-01
    • 2011-06-24
    • 2016-02-12
    相关资源
    最近更新 更多