按顺序运行异步套接字操作

Posted

技术标签:

【中文标题】按顺序运行异步套接字操作【英文标题】:Running async socket operations in order 【发布时间】:2012-07-17 09:24:37 【问题描述】:

我需要的是一个按顺序执行异步操作的类。

class FooSocket

    private Socket _Socket;

    // Message is a class that wraps a byte array.
    public Task<Message> Receive()  /*Bla...*/ ;
    public Task<int> Send(Message message)  /*Bla...*/ ;

如果我按Send、Receive和Send的顺序调用,我需要先发送,并将剩余的接收和发送操作排队,直到第一个接收完成。

我尝试在课堂上创建一个主要任务字段并遵循MainTask = MainTask.ContinueWith(...) 类型的方法。我什至写了一个名为 Sequencer 的类,它正是这样做的,但不知何故感觉不对,在延续和其他东西中创建嵌套任务(使用 Task.Factory.FromAsync 方法)。

我还尝试做一些事情,比如排队 TaskCompletionSource 对象并在我的 Receive/Send 方法中返回它们的任务,在一个单独的线程上以无限循环检查队列,但由于我将有大约 200k 的 FooSocket 实例,一个线程用于各自也觉得不明智。如果我把它做成一个线程池,我会得出这个“线程池不应该用于长时间运行的操作”的规则。

我感觉很接近,但不确定订购这些工作的最有效方式是什么。

【问题讨论】:

如果您可以使用 C#5 或异步扩展,甚至更好的 F#,如果不是,那么您应该使用 Task.FromAsync/Task.ContinueWith 方式,恕我直言 您想同步运行异步操作吗? @Carsten,我需要在 C# 4 中完成。 @Jodrell,有点;当涉及到它们自己的操作时,所有 FooSocket 实例都应该同步工作,而从调用者的角度来看是异步的。 @d4wn:或多或少是微不足道的——你基本上只需要添加一些 async/await 关键字——你可以在这里找到很多示例和信息:msdn.microsoft.com/en-us/vstudio/async.aspx 【参考方案1】:

我会使用TPL Dataflow。您可以安装它via NuGet 或作为Async CTP 的一部分。 TPL Dataflow 提供了一个基本的 BufferBlock&lt;T&gt; 类型,听起来正是您所需要的。

如果你只是建模一个套接字,那么当数据被缓冲出去时完成Send任务,不断地读入另一个缓冲区,当你从那个缓冲区读取时完成Receive任务。 (注意:Socket 上的“发送”操作在数据缓冲到操作系统时完成,而不是在数据通过线路输出或到达目的地时完成。

如果您正在为更高级别的命令/响应建模,那么您应该有一个代表整个命令/响应的任务,正如 James 所建议的那样。我会两者兼而有之;借助async/await 支持,可以轻松将一个层叠在另一个之上。 (注意:Socket 上的“接收”操作可能会以部分接收完成,因此您需要 message framing)。

您的架构可能还需要一些工作:

我将拥有大约 20 万个 FooSocket 实例

这肯定是个问题(我假设您使用的是 TCP/IP)。只有大约 65K TCP/IP 端口,默认情况下只有大约 16K 是短暂的,您必须为操作系统留出大量“喘息空间”,否则它会开始出现异常行为。我估计只有约 12K 的连接是现实的,除非您更改可以(理论上)使您达到约 59K 的短暂范围。大约 200K 是不可能的 - 除非您更改临时范围并且使用负载均衡器拥有多个 IP 地址。

【讨论】:

关于 BufferBlock,MSDN page of it 没有任何关于使用的信息,在找到 this 之后,我仍然很难理解如何在我的场景中使用它。我也不太明白你的第二段(对不起,新的套接字)。我阅读了您的消息农场帖子,它很棒,但是我发送数据的设备的软件超出了我的控制范围,并且无法理解前缀长度。我只是将命令分成一大块发送并阅读,直到我看到 . 正如您所说的那样,这是不可能的,我还需要连接到大约 200k 的这些设备才能与它们进行交互,但我最多可以使用 5 台服务器来实现这一点。无论如何,短期内10k就足够了。在那之后,我将有足够的时间研究更明智的方式,比如云或足够的服务器场......还不知道。 我的 first link 是一个介绍性 TPL 数据流文档。并且消息框架可以很好地与分隔符配合使用;如果可以选择,我只是更喜欢长度前缀。 对不起,我想我很草率,看到“下载中心”让我觉得它是一个安装程序。我肯定会在几分钟内调查一下。但就像我说的那样,我无法控制我需要与之通信的设备软件(接收代码)。因此,在此特定示例中,分隔符与长度前缀没有什么不同,因为我们的设备都不支持,至少在当前版本中是这样。 啊,我以为 你的意思是分隔符。如果您的意思是流的实际结束,那将是非常低效的。但如果你没有选择,那么你就别无选择。 :)【参考方案2】:

如果它是请求/响应类型的行为,恕我直言,任务粒度应该是完整的往返,而不是分开发送和接收。

您不需要 CTP 来支持 .net 4,您可以使用异步定位包。

消费代码是什么样的?带有等待调用的循环?

【讨论】:

以上是关于按顺序运行异步套接字操作的主要内容,如果未能解决你的问题,请参考以下文章

在后台线程上执行异步套接字

套接字异步操作会同步完成吗?

.Net 异步套接字操作限制?

为异步龙卷风 Web 套接字服务器编写同步测试套件

按顺序运行异步操作

"现在已经正在使用此 SocketAsyncEventArgs 实例进行异步套接字操作"的处理