C# SocketAsyncEventArgs 停止触发完成事件

Posted

技术标签:

【中文标题】C# SocketAsyncEventArgs 停止触发完成事件【英文标题】:C# SocketAsyncEventArgs stops firing completed event 【发布时间】:2013-11-06 22:54:51 【问题描述】:

我注意到一个问题,即 SocketAsyncEventArgs 的 .Completed 事件似乎停止触发。同一个 SAEA 可以正常触发并在池中多次替换,但最终所有实例都将停止触发,并且由于在池中替换它们的代码位于事件处理程序中,因此池为空。

以下情况显然也是正确的:

1) 它似乎只发生在服务器端套接字向其中一个连接的客户端发送数据时。当同一个类作为客户端连接时,它不会出现故障。

2) 它似乎在高负载下发生。线程数似乎会逐渐增加,直到最终发生错误。

3) 在类似压力下的测试台似乎永远不会发生故障。 (每秒只有 20 条消息,并且测试台已经证明可以达到 20K)

我将无法粘贴相当复杂的代码,但这里是我的代码描述

1) 主要灵感是这样的:http://vadmyst.blogspot.ch/2008/05/sample-code-for-tcp-server-using.html。它展示了如何使用事件连接完成端口,如何通过 TCP 连接获取不同大小的消息,等等。

2) 我有一个字节缓冲区,其中所有 SAEA 都有一块,不重叠。

3) 我有一个基于阻塞集合的 SAEA 对象池。如果池空的时间过长,则会抛出此错误。

4) 作为服务器,我保留了一组从 AcceptAsync 函数返回的套接字,这些套接字由客户端的端点进行索引。单个进程可以将一个实例用作服务器,也可以将多个实例用作客户端(形成 Web)。它们共享 SAEA 的数据缓冲区和池。

我意识到这很难解释;我已经调试了整整一天一夜。只是希望有人听说过这个或有有用的问题或建议。

目前,我怀疑某种线程耗尽,导致 SAEA 无法调用完成。或者,传出缓冲区存在某种缓冲区问题。

【问题讨论】:

seems to stop firing 这可能是一种误解。也许它正在触发,但您的代码没有正确处理该事件。没有代码,几乎不可能帮助您。要么发布代码,要么创建一个非常少的代码行的小副本(这可能会导致首先发现错误)。 我现在在家,所以不能手。我发现这个例子很接近:netrsc.blogspot.com/2010/05/… 他的代码以完全相同的方式处理返回。直接到 processSend 函数或间接通过 iocompleted 事件处理程序。 【参考方案1】:

所以,又调试了一天,终于有一个解释了。

1) SAEA 没有触发完成的事件,因为它们无法发送更多。 Wireshark 发现这是由于 TCP 窗口清空所致。 (TCP 零窗口)

2) TCP 窗口正在清空,因为网络层正在将一个事件向上传递到堆栈,该事件需要很长时间才能完成,即网络层和 UI 之间没有生产者/消费者。因此,网络操作在发送 ACK 之前必须等待屏幕绘制。

3) 耗时过长的事件是 GUI 上的事件处理程序中的屏幕绘制。测试台是一个控制台窗口(一个汇总传入消息的窗口),所以这就是它在更高负载下没有引起问题的原因。在每条消息上不重绘屏幕是正常的,但发生这种情况是因为项目尚未完成。重绘率稍后会修复。

4) 短期解决方案是确保没有 GUI 阻碍演出。更稳健的解决方案可能是在网络层创建生产者/消费者。

【讨论】:

我在这里写过这个问题:serverframework.com/asynchronousevents/2011/06/…

以上是关于C# SocketAsyncEventArgs 停止触发完成事件的主要内容,如果未能解决你的问题,请参考以下文章

C# SocketAsyncEventArgs 和网络故障

C#高性能大容量SOCKET并发:SocketAsyncEventArgs封装

SocketAsyncEventArgs 和缓冲,而消息是在部分

C# IOCP完成端口模型(简单实用高效)

是否有必要清理 SocketAsyncEventArgs.Completed?

为啥 SocketAsyncEventArgs.RemoteEndpoint 返回 null? C#