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

时间:2012-07-17 09:24:37

标签: c# sockets asynchronous task-parallel-library asyncsocket

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

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...*/ };
}

如果我按此顺序呼叫发送,接收和发送,我需要先发送并排队剩余的接收和发送操作,直到第一次接收完成。

我尝试在课堂上创建一个主要任务字段,并遵循MainTask = MainTask.ContinueWith(...)方法。我甚至写了一个名为Sequencer的类,它确实做到了这一点,但它在某种程度上感觉不对,在continuation和stuff中创建了嵌套任务(使用Task.Factory.FromAsync方法)。

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

我感觉很亲密,但无法确定订购这些工作的最有效方式是什么。

2 个答案:

答案 0 :(得分:2)

我会使用TPL Dataflow。您可以将其安装为via NuGet,也可以将其作为Async CTP的一部分进行安装。 TPL Dataflow提供基本BufferBlock<T>类型,听起来就像您需要的那样。

如果您只是对套接字进行建模,那么在缓冲数据时将完成Send任务,继续读入另一个缓冲区,并在读取时完成Receive任务缓冲。 (注意:Socket上的“发送”操作在数据缓冲到操作系统时完成,而不是在线路上或到达目的地时完成。

如果您正在为更高级别的命令/响应建模,那么您应该有一个代表整个命令/响应的任务,正如James建议的那样。我会两个都做;通过async / await支持,可以轻松地将其中一个分层。 (注意:Socket上的“接收”操作可以通过部分接收完成,因此您需要message framing

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

  

我将拥有大约200k的FooSocket实例

这肯定是个问题(我假设您正在使用TCP / IP)。默认情况下只有~65K TCP / IP端口,其中只有~16K是短暂的,你必须为操作系统留下大量的“喘息空间”或者它开始行为不端。我估计只有~12K的连接是现实的,除非你改变短暂的范围,理论上可以达到~59K。 〜200K是不可能的 - 除非您更改短暂范围具有多个带有负载均衡器的IP地址。

答案 1 :(得分:1)

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

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

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