阻塞套接字:确切地说,“send()"何时执行?返回? [英] Blocking sockets: when, exactly, does "send()" return?

查看:12
本文介绍了阻塞套接字:确切地说,“send()"何时执行?返回?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

确切地说,BSD 套接字 send() 函数何时返回调用者?

When, exactly, does the BSD socket send() function return to the caller?

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

In non-blocking mode, it should return immediately, correct?

至于阻塞模式,man页面说:

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

When the message does not fit into the send buffer of the socket, send() normally blocks, unless the socket has been placed in non-blocking I/O mode.

问题:

  1. 这是否意味着如果内核发送缓冲区中有空间,send() 调用总是会立即返回?
  2. send() 调用的行为和性能对于 TCP 和 UDP 是否相同?如果没有,为什么不呢?
  1. Does this mean that the send() call will always return immediately if there is room in the kernel send buffer?
  2. Is the behavior and performance of the send() call identical for TCP and UDP? If not, why not?

推荐答案

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

Does this mean that the send() call will always return immediately if there is room in the kernel send buffer?

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

Yes. As long as immediately means after the memory you provided it has been copied to the kernel's buffer. Which, in some edge cases, may not be so immediate. For instance if the pointer you pass in triggers a page fault that needs to pull the buffer in from either a memory mapped file or the swap, that would add significant delay to the call returning.

对于 TCP 和 UDP,send() 调用的行为和性能是否相同?如果没有,为什么不呢?

Is the behavior and performance of the send() call identical for TCP and UDP? If not, why not?

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

Not quite. Possible performance differences depends on the OS' implementation of the TCP/IP stack. In theory the UDP socket could be slightly cheaper, since the OS needs to do fewer things with it.

另一方面,由于您可以使用 TCP 每次系统调用发送更多数据,通常使用 TCP 时每字节的成本会低很多.这可以通过最近的 linux 内核中的 sendmmsg() 来缓解.

On the other hand, since you can send much more data per system call with TCP, typically the cost per byte can be a lot lower with TCP. This can be mitigated with sendmmsg() in recent linux kernels.

至于行为,几乎相同.

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

For blocking sockets, both TCP and UDP will block until there's space in the kernel buffer. The distinction however is that the UDP socket will wait until your entire buffer can be stored in the kernel buffer, whereas the TCP socket may decide to only copy a single byte into the kernel buffer (typically it's more than one byte though).

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

If you try to send packets that are larger than 64kiB, a UDP socket will likely consistently fail with EMSGSIZE. This is because UDP, being a datagram socket, guarantees to send your entire buffer as a single IP packet (or train of IP packet fragments) or not send it at all.

非阻塞套接字的行为与阻塞版本相同,唯一的例外是调用失败并显示 EAGAIN(或 EWOULDBLOCK).发生这种情况时,是时候将套接字放回 epoll/kqueue/select(或您正在使用的任何东西)以等待它再次变为可写状态.

Non blocking sockets behave identical to the blocking versions with the single exception that instead of blocking (in case there's not enough space in the kernel buffer), the calls fail with EAGAIN (or EWOULDBLOCK). When this happens, it's time to put the socket back into epoll/kqueue/select (or whatever you're using) to wait for it to become writable again.

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

As usual when working on POSIX, keep in mind that your call may fail with EINTR (if the call was interrupted by a signal). In this case you most likely want to call send() again.

这篇关于阻塞套接字:确切地说,“send()"何时执行?返回?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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