使用管道()和剪接()将数据发送到多个插座[英] Send data to multiple sockets using pipes, tee() and splice()

本文是小编为大家收集整理的关于使用管道()和剪接()将数据发送到多个插座的处理方法,想解了使用管道()和剪接()将数据发送到多个插座的问题怎么解决?使用管道()和剪接()将数据发送到多个插座问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

我正在用Tee()复制一个"主管",以使用splice()写入多个插座.自然,这些管道会以不同的速率清空,具体取决于我可以拼接到目标插座的多少.因此,当我接下来要将数据添加到"主管"中,然后再次将数据添加到Tee()时,我可能会有一种情况,可以将64KB写入管道,而只需将Tee 4KB写入其中一个"从属"管道.我猜想,如果我将所有"主管"拼写到插座上,我将永远无法将剩余的60kb击中到该从管道上.真的吗?我想我可以跟踪tee_offset(从0开始)设置为" un -teed"数据的开始,然后不要拼写过去.因此,在这种情况下,我将TEE_OFFSET设置为4096,并且直到我能够将其全部交给其他管道之前,我的剪接不超过它.我在正确的轨道上吗?我有任何提示/警告吗?

推荐答案

如果我理解正确,则您有一些实时数据源,要将这些数据源用于多个插座.您已经有一个连接到生产数据的单个"源"管,并且为您希望发送数据的每个插座都有一个"目的地"管道.您要做的是使用tee()将数据从源管复制到每个目标管道,然后splice()将其从目标管道复制到插座本身.

您将要在此处遇到的基本问题是,如果其中一个插座无法跟上 - 如果您要更快地生产数据,那么您将遇到问题.这与您使用管道无关,这只是一个基本问题.因此,您需要选择一种在这种情况下应付的策略 - 我建议处理此操作,即使您不希望它很普遍,因为这些事情经常稍后会咬您.您的基本选择是关闭有问题的套接字,或者跳过数据,直到清除其输出缓冲区为止 - 后者的选择可能更适合音频/视频流.

与您使用的管道有关的问题是,在Linux上,管道缓冲区的大小在某种程度上是不灵活的.由于Linux 2.6.11(tee()呼叫在2.6.17中添加) - 请参见管道manpage .由于2.6.35可以通过F_SETPIPE_SZ选项更改此值,为fcntl()(请参阅 epoll()等待源管中有一些东西.

  • 在所有目标管道上循环read_counter为零,调用tee()将数据传输到每个数据.确保在标志中通过SPLICE_F_NONBLOCK.
  • 增加每个目的地管的read_counter按tee()传输的数量.跟踪最低的结果值.
  • 找到read_counter的最低结果值 - 如果这不是零,则从源管中丢弃该数据量(例如,使用splice()调用,例如在/dev/null上打开的目标).丢弃数据后,减去从 on of the Pipes上丢弃的数量(由于这是最低的值,所以这不能导致任何一个变为负).
  • 从步骤重复 3 .
  • 注意:过去绊倒了我的一件事是,SPLICE_F_NONBLOCK会影响管道上的tee()和splice()操作是否是非阻滞,而您设置了用fnctl()设置的O_NONBLOCK与其他呼叫的相互作用(例如read()和write())是否是非阻滞.如果您希望一切都不障碍,请两者都设置.还要记住要使您的插座非阻滞或splice()调用将数据传输到他们的电话可能会阻止(除非您想要的是您想要的,如果您使用的是螺纹方法).

    您可以看到,此策略有一个主要问题 - 一旦一个插座块抬起,所有东西都停止了 - 该插座的目标管将填充,然后源管将停滞不前.因此,如果您到达tee()返回EAGAIN EAGAIN的阶段循环)使得您不会写任何其他内容,直到其输出缓冲区为空为止.您选择的取决于您的数据流是否可以从跳过的位中恢复.

    如果您想更优雅地应对网络延迟,那么您将需要进行更多的缓冲,这将涉及用户空间缓冲区(这否则否定了tee()和splice()的优点)或基于磁盘的缓冲区.基于磁盘的缓冲几乎肯定会比用户空间缓冲慢得多,因此,由于您首先选择了tee()和splice(),因此不合适,但我提到它是为了完整的.

    值得注意的一件事,如果您最终在任何时候从用户空间插入数据是vmsplice()呼叫,它可以以与致电.如果您进行足够的缓冲以使数据将数据分配在多个不同的分配缓冲区之间(例如,如果您使用池分配方法方法).

    最后,您可以想象在使用tee()和splice()的"快速"方案之间交换插座,如果它们不跟上来,则将其移至较慢的用户空间缓冲.这会使您的实现复杂化,但是如果您要处理大量连接,并且其中只有很小的比例很慢,那么您仍将复制到涉及的用户空间的复制量.但是,这仅是应对瞬态网络问题的短期措施 - 正如我最初说的那样,如果您的插座比来源慢,那么您会有一个基本问题.您最终会达到一些缓冲限制,需要跳过数据或关闭连接.

    总的来说,我会仔细考虑您为什么需要tee()和splice()的速度,并且对于您的用例,仅在内存中还是在磁盘上进行用户空间缓冲是否更合适.但是,如果您有信心速度总是很高,并且可以接受有限的缓冲,那么我上面概述的方法应该起作用.

    另外,我应该提到的一件事是,这将使您的代码非常特定于Linux - 我不知道这些调用是其他UNIX变体中的支持. sendfile()呼叫比splice()更限制,但可能更便携.如果您真的希望东西便携式,请坚持使用用户空间缓冲.

    让我知道我是否涵盖了您想要更多细节的内容.

    本文地址:https://www.itbaoku.cn/post/359088.html