代码之家  ›  专栏  ›  技术社区  ›  Poni

用TCP实现一个性能良好的“发送”队列

  •  0
  • Poni  · 技术社区  · 14 年前

    为了不淹没远程端点,我的服务器应用程序必须实现一个“发送”队列,其中包含我希望发送的数据包。

    我使用Windows Winsock,I/O完成端口。

    因此,我知道当我的代码调用“socket->send(…….)”时,我的自定义“send()”函数将检查数据是否已经“在线”(朝向该套接字)。
    如果一个数据确实在线路上,它将简单地对稍后发送的数据进行排队。
    如果线路上没有数据,它将调用wsasend()来真正发送数据。

    到目前为止一切都很好。

    现在,我要发送的数据的大小是不可预测的,所以我把它分成更小的块(比如64字节),以避免将内存浪费在小数据包上,并对这些小数据块进行排队/发送。

    当IOCP给出关于我发送的数据包的“写入完成”完成状态时,我发送队列中的下一个数据包。

    这就是问题所在,速度太低了。 我实际上得到了,它在本地连接(127.0.0.1)上的速度是200kb/s。

    所以,我知道我必须用七个块(wsabuf对象数组)调用wsasend(),这将提供更好的性能,但是,我一次要发送多少?
    是否有建议的字节大小?我相信答案是特定于我的需要,但我也肯定有一些“一般”的要点要开始。
    还有其他更好的方法吗?

    1 回复  |  直到 13 年前
        1
  •  1
  •   Len Holgate    13 年前

    当然,如果您试图发送的数据速度超过对等方处理数据的速度(可能是由于链接速度或对等方读取和处理数据的速度),则只需使用提供自己的队列。如果您想控制正在使用的系统资源的数量,那么您只需要使用自己的数据队列。如果你只有几个连接,那么这很可能是不必要的,如果你有1000,那么这是你需要关心的事情。这里要认识到的主要事情是,如果您在Windows上使用任何异步网络发送API,不管是托管的还是非托管的,那么您将控制发送缓冲区的生存期,并将其传递给接收应用程序和网络。见 here 了解更多详细信息。

    一旦你决定你确实需要为此烦恼,那么你就不必总是烦恼,如果对等方处理数据的速度比你能生成数据的速度快,那么就没有必要通过在发送方排队来减慢速度。您将看到您需要对数据进行排队,因为您的写入完成将开始花费更长的时间,因为由于流控制问题,TCP堆栈无法发送更多的数据,您发出的重叠写入无法完成(请参见 http://www.tcpipguide.com/free/t_TCPWindowSizeAdjustmentandFlowControl.htm )此时,您可能正在使用不受限制的有限系统资源量(非分页池内存和可以锁定的内存页数量都是有限的,并且(据我所知)这两者都由挂起的套接字写入使用)。

    不管怎样,够了…我假设您在添加发送队列之前已经获得了良好的吞吐量?要获得最大性能,您可能需要将TCP窗口大小设置为大于默认值的值(请参见 http://msdn.microsoft.com/en-us/library/ms819736.aspx )并在连接上发布多个重叠的写入。

    假设您已经具有良好的吞吐量,那么您需要在开始排队之前允许一些挂起的重叠写入,这将使准备发送的数据量最大化。一旦您有了等待写入的神奇数量,就可以开始对数据进行排队,然后根据后续的完成情况发送数据。当然,一旦有任何数据排队,所有进一步的数据都必须排队。使数字可配置并进行配置,以查看在速度和使用的资源(即您可以维护的并发连接数)之间进行权衡时最有效的方法。

    我倾向于对整个数据缓冲区进行排队,这将作为数据缓冲区队列中的单个条目发送,因为您使用的是IOCP,所以这些数据缓冲区可能已经被引用计数,以便在完成时(而不是之前)轻松释放,因此排队过程变得更简单,因为您只需持有对T的引用。当数据在队列中时,他发送缓冲区,并在发出发送后释放缓冲区。

    就我个人而言,我不会通过将分散/收集写入与多个wsabuf一起使用来优化,除非您有基础工作,并且您知道这样做实际上会提高性能,我怀疑如果您已经有足够的待处理数据,它将是最佳的;但和往常一样,测量和您将知道。

    64字节太小。

    你可能已经看到了这个,但我在这里写的主题是: http://www.lenholgate.com/blog/2008/03/bug-in-timer-queue-code.html 虽然对你来说可能太模糊了。