SocketAsyncEventArgs ReceiveAsync限制(未调用arg.Complete)

时间:2014-12-19 12:45:08

标签: c# sockets tcp

我们有一个非常标准的SocketAsyncEventArgs TCP实现(对于你可以google的众多例子没有真正的区别)。

我们有一个负载测试控制台应用程序(也使用SocketAsyncEventArgs),每秒发送x条消息。我们使用线程旋转在1000ms内引入大部分准确的时间间隔来发送消息(而不是尽可能快地发送x消息,然后等待1000ms的剩余时间)。

我们发送的消息大小约为2k,服务器实现使用预先分配的HTTP OK 200响应响应(在同一个套接字上)。

我们希望能够使用SocketAsyncEventArgs每秒发送100个消息而不是1000个消息。我们发现通过简单的阻塞TcpListener / TcpClient,我们能够处理~150msg / s。然而,即使在20秒内每秒只有50条消息,我们平均会丢失1000条消息中的27条。

这是一个TCP实现,所以我们当然希望不会丢失任何消息;特别是考虑到这么低的吞吐量。

我正在努力避免粘贴整个实现(~250行),但如果您认为它有帮助,可根据要求提供代码。我的问题是,我们应该从SAEA那里得到什么 load ?鉴于我们为接受/接收/发送args预先分配了单独的池,我们已经确认这些池永远不会被饿死,为什么我们没有收到每条消息的arg.Complete回调?

注意:执行期间未见到套接字错误

回复评论

@usr:和你一样,我们担心我们的实施可能会出现严重问题。为了确认这一点,我们从this popular Code Project example project获取了可下载的zip。我们调整了负载测试解决方案以使用新示例并重新运行我们的测试。我们使用其他人的代码经历了完全相同的结果(这主要是我们决定接近SO社区的原因)。

我们发送50 msg / sec持续20秒,代码项目示例和我们自己的代码平均导致973/1000次接收操作。请注意,我们在最基本的水平上进行了测量,以降低不正确监控的风险。也就是说,我们在Interlocked.Increment方法上使用onReceive的静态int - onComplete仅调用异步操作,onReceiveonComplete调用何时!willRaiseEvent

使用环回地址在单台机器上执行所有操作。

遇到两个完全不同的实现问题,然后我们怀疑我们的负载测试实现。我们通过Wireshark确认我们的负载测试项目确实按预期发送了流量(碎片存在于pcap日志中,但wireshark表示数据包按预期重新组装)。我承认,我在低级别的网络理解比我想要的要弱,但考虑到碎片的数量远远不及匹配丢失消息的数量,我们现在假设两者没有关系。正如我所说,碎片应该在较低层处理,并在我们的API调用级别完全抽象。

@Peter,

公平地说,在正常的网络场景中,这样的定时精度水平将是完全没有意义的。但是,等待实现非常简单,wireshark确认我们的消息时间与pcap日志的精度允许一样准确。鉴于我们仅测试环回(相同的代码已经部署到Azure云服务,一旦它是生产级别,它也是代码的预期目的地,但是在A0,A1和A8实例上发现相同但不会更糟的结果),我们想确保一定程度的节流。如果没有限制,代码可以在几毫秒内轻松推送1000个异步args,这不是我们所瞄准的压力水平。

我同意,鉴于它是一个TCP实现,我们的代码中必定存在错误。你知道the linked Code Project example中的任何错误吗?因为它表现出与我们的代码相同的问题。

1 个答案:

答案 0 :(得分:0)

  

@usr,正如预测的那样,缓冲区确实包含多条消息。我们现在需要弄清楚我们如何将消息结合在一起(TCP保证交付顺序,但在使用多个SAEA时,我们通过线程失去了保证)。

最好的解决方案是放弃自定义TCP协议。例如,使用HTTP和协议缓冲区。或者,Web服务。对于所有这些,可以使用快速且易于使用的异步库。假设这不是你想要的:

定义消息框架格式。例如,为每条消息添加BitConvert.GetBytes(messageLengthInBytes)。这样你就可以解构流。