Tcp 阻塞套接字:确切地说,什么时候;发送();返回?

Tcp 阻塞套接字:确切地说,什么时候;发送();返回?,tcp,udp,sockets,Tcp,Udp,Sockets,BSD套接字send()函数何时返回调用方 在非阻塞模式下,它应该立即返回,对吗 至于阻塞模式,则说明: 当消息不适合套接字的发送缓冲区时,send()通常会阻塞,除非套接字已置于非阻塞I/O模式 问题: 这是否意味着如果内核发送缓冲区中有空间,那么send()调用总是会立即返回 TCP和UDP的send()调用的行为和性能是否相同?若否,原因为何 这是否意味着send()调用 将始终立即返回,如果 内核中有空间 缓冲区 不是吗?数据“发送”之后的时间可以用不同的定义。我认为这是操作系统接受您的

BSD套接字
send()
函数何时返回调用方

在非阻塞模式下,它应该立即返回,对吗

至于阻塞模式,则说明:

当消息不适合套接字的发送缓冲区时,send()通常会阻塞,除非套接字已置于非阻塞I/O模式

问题:

  • 这是否意味着如果内核发送缓冲区中有空间,那么
    send()
    调用总是会立即返回
  • TCP和UDP的
    send()
    调用的行为和性能是否相同?若否,原因为何
  • 这是否意味着send()调用 将始终立即返回,如果 内核中有空间 缓冲区

    不是吗?数据“发送”之后的时间可以用不同的定义。我认为这是操作系统接受您的数据以在堆栈上交付的时刻。否则很难定义它。是数据传输到网卡缓冲区的时刻吗?还是在数据被推出网卡缓冲区之后


    你有什么问题需要肯定地知道吗?或者你只是好奇而已?

    你的假设是正确的。如果内核发送缓冲区中有空间,内核将把数据复制到发送缓冲区,并且
    send()
    将返回。

    如果内核缓冲区中有空间,那么
    send()
    将尽可能多的字节复制到缓冲区中,并立即退出,返回实际复制的字节数(可以少于您请求的数量)。如果内核缓冲区中没有空间,则
    send()
    会阻塞,直到其中一个空间可用或出现超时(如果已配置)

    这是否意味着如果内核发送缓冲区中有空间,send()调用总是会立即返回

    是的。只要立即意味着在您提供的内存被复制到内核的缓冲区之后,它就被复制到内核的缓冲区。在某些边缘情况下,这可能不是那么立即。例如,如果您传入的指针触发了一个页面错误,需要从内存映射文件或交换中拉入缓冲区,这将给调用r增加很大的延迟翻转

    TCP和UDP的send()调用的行为和性能相同吗?如果不相同,为什么不相同

    不完全一样。可能的性能差异取决于操作系统对TCP/IP堆栈的实现。理论上,UDP套接字可能会稍微便宜一些,因为操作系统需要用它做的事情更少

    EDIT:另一方面,由于使用TCP可以在每次系统调用中发送更多的数据,因此使用TCP时每个字节的成本通常会低得多。使用最新的linux内核可以缓解这一问题

    至于行为,几乎是一样的

    对于阻塞套接字,TCP和UDP都将阻塞,直到内核缓冲区中有空间为止。然而,区别在于UDP套接字将等待整个缓冲区可以存储在内核缓冲区中,而TCP套接字可能决定只将单个字节复制到内核缓冲区中(但通常不止一个字节)

    如果您尝试发送大于64kiB的数据包,UDP套接字可能会始终失败,并且EMSGSIZE。这是因为UDP作为数据报套接字,保证将整个缓冲区作为单个IP数据包(或IP数据包片段序列)发送,或者根本不发送

    非阻塞套接字的行为与阻塞版本相同,但有一个例外,即不是阻塞(如果内核缓冲区中没有足够的空间),而是通过EAGAIN(或eWoldBlock)调用失败。当发生这种情况时,是时候将套接字放回epoll/kqueue/select(或您正在使用的任何内容)等待它再次变为可写

    与往常一样,在POSIX上工作时,请记住,您的调用可能会因EINTR而失败(如果调用被信号中断)。在这种情况下,您很可能希望再次调用
    send()

    内核接受数据后,send()将立即返回。 在阻塞套接字的情况下:如果内核缓冲区没有足够的空闲空间来接收提供给send()调用的数据,send()将阻塞


    非阻塞套接字:send()不会阻塞,但会失败并返回-1,或者它可能返回部分复制的字节数(取决于可用的缓冲区空间)。它设置errno eWoldBlock或EAGAIN。这意味着在send()时,缓冲区无法容纳所有字节,您应该使用select()调用send()重试再次读取数据。或者你可以使用sleep()和call send()进行循环,但你必须考虑实际发送的字节数和要发送的剩余字节数。

    Er,我试图确定函数调用是否会阻塞任何类型的I/O,如果是,会阻塞多长时间。这不是一个存在的问题:-)如果TCP套接字只复制缓冲区的一部分,这是如何工作的?它只是返回一个写值<您的消息长度吗?如果它返回EAGAIN,那么您无法知道写入了多少字节…EAGAIN不是返回值,而是
    errno
    .send()的值在TCP套接字上,它会告诉您需要多少字节,如果出现错误,则会告诉您需要多少字节或-1。如果出现错误,请查看
    errno
    了解详细信息。EAGAIN意味着它不能再使用了,因为它的发送缓冲区已满(或高于高水位线)巨型帧是比标准大小大的以太网帧-udp本身始终限制为64KiB,巨型帧与否。[…]但是,区别在于udp套接字将等待整个缓冲区存储到内核缓冲区[…]-在BSD系统中不是这样。不幸的是,如果发送缓冲区已满,数据包就会被丢弃。真是太遗憾了!我注意到了