如果应用程序可以确保套接字的发送缓冲区中总是有空间,那么阻塞和非阻塞发送是否具有相同的性能?在这种情况下,这两种方法相比有什么优势吗?
阻塞和非阻塞之间的唯一区别send是内核是将进程置于休眠还是返回EWOULDBLOCK.所以在性能方面,应该没有区别.
但是,我怀疑你的隐含假设是发送不能因为发送缓冲区有空闲空间而阻塞.想象一下系统上的空闲套接字对内存提出了很高的要求.我不一定希望内核"固定"发送缓冲区的物理页面; 我希望它可以将内存用于有用的东西.然后当你尝试发送时,内核需要获取发送缓冲区的空闲页面; 如果没有这样的页面可用,它可能决定返回EWOULDBLOCK而不是等待(比如说)交换.
现在,这是很多"maybes"和"mights",而更熟悉内核内部的人可能会告诉我我错了.但是,即使Linux今天没有这样的行为,它可能明天就会出现; 你是否100%确定你永远不会在除Linux以外的任何东西上运行你的应用程序?
所以我不会用如此脆弱的假设来编写我的应用程序.我建议您决定阻塞或非阻塞语义是否对您自己的代码更有意义,并且不要尝试游戏内核的内部.
[更新]
我希望我不必深入研究Linux内部,但一个过于自信的downvoter驱使我去了它.
从"new_segment"标签处的net/ipv4/tcp.c开始:
new_segment:
if (!sk_stream_memory_free(sk))
goto wait_for_sndbuf;
skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation);
if (!skb)
goto wait_for_memory;
Run Code Online (Sandbox Code Playgroud)
看看"wait_for_sndbuf"与"wait_for_memory"有什么不同?这就是我所说的.
在"wait_for_memory"标签处,调用sk_stream_wait_memory的timeo值取决于这是否为非阻塞发送.反过来,该功能要么使进程处于休眠状态,要么EAGAIN根据情况返回timeo.
[更新2]
只是要清楚我在回答什么问题......
我将这个问题解释为:"如果我知道我的套接字的发送缓冲区有足够的可用空间,send那么套接字上的阻塞和非阻塞之间是否存在差异 - 性能或其他方面?"
例如,如果您的协议要发送一条消息,然后仅在收到对先前消息的回复后发送新消息,则前提当然是可能的.在这种情况下,您知道发送缓冲区始终为空send.通过获取和/或设置POSIX标准SO_SNDBUF套接字选项,您可以知道您的套接字有足够的可用空间.在这种情况下,阻塞send行为可以与非阻塞行为不同send吗?
我对POSIX规范的解读原则上说"是".我阅读Linux源代码在实践中说"是".我当然可能是错的,但是需要更多有关POSIX或Linux的知识来展示它,到目前为止他们都没有回答过这个问题.
[最终(?)更新]
以下是我认为POSIX允许/要求您承担的内容.
如果发送缓冲区中有足够的可用空间,则阻塞send不能永久阻塞.这calloc与使用足够的可用虚拟内存的调用无法永久阻止的意义相同.最终,系统将找到发送数据所需的资源.
(注意,当发送缓冲区已满时,情况并非如此,在这种情况下,阻塞send可能会永久阻塞,具体取决于套接字接收端发生的情况.)
但是,即使发送缓冲区中有足够的空间,send也可能仍会返回非阻塞EWOULDBLOCK.因此,如果您使用非阻塞套接字,则无论您对发送缓冲区或其他任何内容有何了解,您的代码都必须处理此问题.
| 归档时间: |
|
| 查看次数: |
3296 次 |
| 最近记录: |