为了不淹没远程端点,我的服务器应用程序必须实现我希望发送的“发送”数据包队列。
我使用Windows Winsock,I / O完成端口。
所以,我知道当我的代码调用“socket-> send(.....)”时,我的自定义“send()”函数将检查数据是否已经“在线上”(朝向那个插座) 如果数据确实在线上,它将简单地将数据排队以便稍后发送 如果线路上没有数据,它将调用WSASend()来真正发送数据。
到目前为止一切都很好。
现在,我要发送的数据大小是不可预测的,所以我把它分成更小的块(比如64字节),以免浪费小数据包的内存,并排队/发送这些小块。 / p>
当IOCP为我发送的数据包发出“写完”状态时,我会发送队列中的下一个数据包。
这就是问题;速度非常低。 我实际上正在使用本地连接(127.0.0.1)的速度,如200kb / s。
所以,我知道我必须使用seveal chunk(WSABUF对象数组)来调用WSASend(),这会提供更好的性能,但是,我会一次发送多少?
是否有推荐的字节大小?我确定答案是针对我的需求的,但我也确定有一些“一般”的要点可以从一开始。
还有其他更好的方法吗?
答案 0 :(得分:1)
当然,如果您尝试发送数据的速度超过对等方可以处理的速度(由于链接速度或对等方可以读取和处理数据的速度),您只需要提供自己的队列。然后,如果要控制正在使用的系统资源量,则只需要使用自己的数据队列。如果你只有几个连接,那么很可能这都是不必要的,如果你有1000个,那么你需要关注它。这里要实现的主要是,如果您使用任何异步网络在Windows上发送API(托管或非托管),那么您将控制发送缓冲区的生命周期到接收应用程序和网络。有关详细信息,请参阅here。
一旦你确定你需要打扰这个你就不必总是打扰,如果对等方能够比你生成数据更快地处理数据那么就没有必要通过排队来减慢速度寄件人。您将看到需要对数据进行排队,因为由于TCP堆栈由于流控制问题而无法再发送任何数据,因此您的写入完成将开始花费更长时间,因为您发出的重叠写入无法完成(请参阅{{3 }})。此时,您可能正在使用无限制的有限系统资源(非页面缓冲池内存和可以锁定的内存页数都是有限的,并且(据我所知)两者都被挂起的套接字写入使用)。 ..
无论如何,够了......我假设你在添加发送队列之前已经达到了良好的吞吐量?要获得最大性能,您可能需要将TCP窗口大小设置为大于默认值(请参阅http://www.tcpipguide.com/free/t_TCPWindowSizeAdjustmentandFlowControl.htm)并在连接上发布多个重叠写入。
假设您已经拥有良好的吞吐量,那么在开始排队之前需要允许许多待处理的重叠写入,这样可以最大化准备发送的数据量。一旦您有未完成的待处理写入数量,您就可以开始对数据进行排队,然后根据后续完成情况发送数据。当然,只要您有任何排队的数据,所有其他数据必须排队。使数字可配置和配置文件,以查看最佳使用速度和资源之间的权衡(即您可以维护的并发连接数)。
我倾向于将整个数据缓冲区排队,这些缓冲区将作为数据缓冲区队列中的单个条目发送,因为您正在使用IOCP,这些数据缓冲区可能已经被引用计数,以便于发布然后当完成发生而不是之前,因此排队过程变得更简单,因为您只是在数据进入队列时保持对发送缓冲区的引用,并在您发出发送后释放它。
我个人不会通过使用带有多个WSABUF的分散/聚集写入进行优化,直到你有基础工作,并且你知道这样做实际上提高了性能,我怀疑如果你有足够的数据已经挂起;但一如既往,衡量,你会知道。
64个字节太小。
你可能已经看过这个,但我在这里写了关于这个主题的文章:http://msdn.microsoft.com/en-us/library/ms819736.aspx虽然对你来说可能太模糊了。