C# SocketAsyncEventArgs接收异步限制(未调用arg.Complete)

C# SocketAsyncEventArgs接收异步限制(未调用arg.Complete),c#,sockets,tcp,C#,Sockets,Tcp,我们有一个相当标准的SocketAsyncEventArgs的TCP实现,与您可以在google上搜索到的众多示例没有真正的区别 我们有一个负载测试控制台应用程序,它也使用SocketAsyncEventArgs,每秒发送x多条消息。我们使用线程旋转在1000毫秒内引入最精确的间隔来发送消息,而不是尽可能快地发送x条消息,然后等待剩余的1000毫秒过去 我们发送的消息大小约为2k,服务器实现在同一套接字上使用预先分配的HTTP OK 200响应响应对其进行响应 我们希望能够使用SocketAsy

我们有一个相当标准的SocketAsyncEventArgs的TCP实现,与您可以在google上搜索到的众多示例没有真正的区别


我们有一个负载测试控制台应用程序,它也使用SocketAsyncEventArgs,每秒发送x多条消息。我们使用线程旋转在1000毫秒内引入最精确的间隔来发送消息,而不是尽可能快地发送x条消息,然后等待剩余的1000毫秒过去

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

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

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

我试图避免粘贴整个实现,大约250行,但是如果您认为有帮助,可以根据请求提供代码。我的问题是,我们应该期待SAEA带来什么样的负担?既然我们为已确认永不耗尽的Accept/Receive/Send arg预先分配了单独的池,为什么我们不为每条消息接收arg.Complete回调

注意:执行过程中未发现套接字错误

对评论的答复:

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

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

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

在经历了两个完全不同的实现的问题之后,我们怀疑我们的负载测试实现。我们通过Wireshark确认,我们的负载测试项目确实按照预期发送了流量。pcap日志中存在碎片,但Wireshark表示数据包按照预期重新组装。我承认,我在低层次上对网络的理解比我希望的要弱,但考虑到碎片的数量与丢失消息的数量相差甚远,我们现在假设两者没有关联。据我所知,碎片应该在较低的一层处理,并在我们的API调用级别完全抽象

@彼得

公平地说,在一个正常的网络场景中,这样的时间准确性水平是完全没有意义的。然而,等待很容易实现,wireshark确认我们的消息的时间安排与pcap日志的精度一样准确。考虑到我们只是在环回上进行测试,同样的代码已经部署到Azure云服务上,一旦达到生产级别,这也是代码的预期目标,但是在A0、A1和A8实例上发现的结果如果不是更糟的话,也是一样的,我们希望确保某种程度的限制。如果没有节流,代码将很容易在几毫秒内推送1000个异步参数,而这并不是我们想要达到的压力水平

我同意,考虑到它是一个TCP实现,我们的代码中一定有一个bug。您是否注意到了系统中的任何错误?因为它表现出与我们的代码相同的问题

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

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


定义消息框架格式。例如,将BitConvert.GetBytesmessageLengthInBytes前置到每条消息。这样你就可以解构数据流。

与你可以在谷歌上搜索到的众多示例没有真正的区别,这意味着它可能会被彻底破坏:你知道TCP不是基于消息的吗?没有使用TCP接收消息这样的事情。您的代码有一个bug,如果没有它,就找不到它。短代码是必需的,thoug
h、 我们使用螺纹旋转来引入1000ms内最精确的间隔-这可能至少是您问题的一部分。无论如何,这样做是没有意义的;网络I/O甚至没有Windows线程调度那么好的计时特性,所以您的所有努力都白费了。Receive/SendAsync当然应该能够像任何其他套接字API一样执行。如果您正在使用TCP丢失数据,那么您的代码中就有一个bug,句号。最有可能的情况是,您收到了预期的150条消息,但由于您的错误而忽略了其中的2/3条消息。很抱歉冒犯了您。这根本不是目的。通过设定正确的期望来帮助你。我每周回答多个关于TCP代码损坏的问题。你不会相信我所看到的。你知道一个接收操作可以同时接收多条消息吗?codeproject文章中的代码似乎不能处理这种情况。不幸的是@usr,上面的所有内容都不适用于我们。消息长度可变,由第三方产品发送。我们必须接收这些消息,处理/持久化它们,并响应每个ACK样式。我们不能在消息中添加长度标记,也不能将这些消息转换为HTTP传输。好的,第三方协议当然允许单独发送消息。你不能依靠TCP来实现这一点。我不知道该推荐什么,因为我不知道该协议。但这从根本上来说不应该是一个困难的问题。第三方硬件输出可变长度的xml文档。如果我们使用单个SocketAsyncEventArg,我们就可以堆叠字节数组,当然,将流拆分为单独的文档也没有问题。如果我们使用多个SAEA,我们无法保证字节数组块以发送/接收顺序或其他方式保存在内存中,因此将损坏的xml文档结合在一起成为一个问题。你以前有没有遇到过这样的问题,或者有什么建议?目前,我们正在针对单个参数测试负载。我会将NetworkStream连接到套接字,并让XML API从该套接字异步提取,但这不是必需的。我会删除所有基于事件的IO内容。这只是为了节省少量的CPU使用。与XML处理相比,它可以忽略不计。