远程客户端停止接收时的Socket.AsyncSend行为

时间:2011-03-06 00:35:54

标签: .net vb.net sockets

我遇到了一个问题,我有很多AsyncSends正在进行数十个客户端套接字,目前如果任何远程客户端停止接收但实际上没有断开连接,应用程序很快就会吃掉所有的SocketAsyncEventArgs(又名sae)我已预先分配,因为它们没有被释放,因为SendAsync没有完成。显而易见的解决方案是实现每个客户端的发送队列,这听起来很容易,但我不清楚具体细节。我有一个sae分配给每个客户端接收,这是完美的,理想情况下我喜欢将单个sae分配给客户端的异步发送。

我理解弹出并询问一个隐藏的问题请求“给我代码”的解决方案被忽视,但老实说,无论是在.XAsync方法上,我都无法提出很多问题。有一个非常糟糕的例子,一般的发送队列。

编辑@ J.N。

我忘了提及它,但我 - 实际上使用了一堆预先分配的sae存储在内部使用ConcurrentBag的管理类中。通过一个连接,在每秒发送20条小消息的测试场景中(实际在生产服务器中实际发送的消息数量略多于两倍),服务器会在几秒钟内耗尽500个预先分配的sae。如果我实现'create if empty'代码,sae计数很快就会增加到数千个。

我理解Socket类的异步方法提供的功能,但是如果有网络打嗝或类似的东西,这个问题将在几秒钟内彻底轰炸服务器。发送队列听起来像是一个很好的解决方案,但我不知道在高性能生产环境中是否做一个好主意。

然而,基本问题仍然存在,即每个客户端每秒发送十几条消息,任何网络拥塞或其他滞后连接但不断开连接的因素都会迅速恶化为一个滞后的混乱。

我认为我可能正在寻找的解决方案是锁定用于发送的单个sae,直到达到完成回调,然后解锁该sae然后重新使用以发送任何待处理数据。然而,实际的实现却使我无法实现。

1 个答案:

答案 0 :(得分:0)

在开始阅读之前,请确保您已经使用并了解Socket.SendTimeout

我建议采用两种不同的方法:

  • 首先,您可以尝试使用sae池。最好的类是ConcurrentBag(我想你需要线程安全)。我们在公司的缓冲池中做了这个,我们在ConcurentBag周围做了一个小包装器,如果碰巧池是空的,它会创建新对象。在您的用例中,您应该考虑断开客户端。当然你需要为每个连接都有一个这样的池,所以我建议使用在套接字上索引的字典。它有点难看,但它确实有效。

  • 其次,您可以实现自己的发送队列,但是您将复制.Net中的异步功能(并且可能会使其变得更糟)。您需要自己的线程和要发送的队列(同步的)消息。当您执行发送时,您需要将消息推送到队列中。后台发送将定期检查队列的状态,如果不是空,则弹出几条消息并同步发送。每次在队列中添加内容以唤醒后台线程时,我建议使用AutoResetEvent。