我正在使用原始TCP套接字与中央服务器进行通信的客户端应用程序。应用程序消息被序列化,然后以长度为前缀创建传递到TCP流中的帧。使用基于任务的异步模式(TAP)的高效套接字I/O
处理此问题的一个经典方法是直接调用socket类上的Receive或BeginReceive,将回调中的消息反序列化,将消息传递到另一个线程处理的单独队列中,然后让回调开始另一个接收再次插座。
这种方法的天真实现对我来说并不理想 - 它紧密地将消息序列化和反序列化耦合到套接字,并需要相当多的“管道”才能让队列在不同的线程/回调中良好地发挥作用。它也是一种漏洞抽象 - 它需要调用代码掌握底层套接字的知识,而不是输入和输出消息的“数据流”。
鉴于我完全在.NET 4.5中工作,使用TPL(TaskFactory.FromAsync)封装Socket的Begin和End异步方法是一个明显的选择。但是,我不清楚如何从这一点出发,原因有很多:
- 我需要一个从未完成接收数据的异步“任务”。只要套接字已连接,我想要处理一个消息流。任何中断(断开连接,套接字错误或取消请求)都是例外情况,而不是传统的任务完成。根据Stephen Toub(http://blogs.msdn.com/b/pfxteam/archive/2011/10/02/10218999.aspx),我应该总是完成我的任务。这造成了一些问题 - 套接字接收在传统意义上从未完成。 Stephen似乎在他的“等待套接字操作”的帖子里稍微有点矛盾,他在那里显示了一个没有套接字错误永不完成的套接字读取(http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx)。
- 我需要一种同步“排队”数据发送的方法。呼叫者应该能够发送消息而不被阻塞,并且消息应该通过套接字顺序传输。换句话说,由于消息成帧,一次只有一个发送给套接字本身。 TPL数据流是否合适,或者我应该使用不同的排队模式?
- 我想在消息序列化和消息传输之间清晰分离关注点。
我还没有看到这种策略类型的很多例子,只有“直接”的套接字I/O或微不足道的实现。我的直觉告诉我,TPL Dataflow非常适合,因为序列化和反序列化可以流水线化。
我不清楚如何在TPL Dataflow或类似的东西之间架设一个有效的无限接收任务链。
任何想法?
神奇的信息。你觉得在API设计方面,“外部”(不确定)接收方法返回标记为“长时间运行”的任务并且永远不会转换到完成状态是可以接受的吗? (即/任务最终总是以已取消或故障结束,从未完成 - 套接字关闭是一种故障形式)。另一种选择是向外部类公开相同的“单个接收每个消息”语义,并构建一个适配器,以某种方式将其连接到TPL数据流缓冲区。适配器将管理接收的“生命周期”。 – ShadowChaser
只要“任务”完成,没关系(它不必有成功完成*的机会)。 'LongRunning'不适用于'async'任务;别担心。在某些时候,你需要一个适配器(比如'FuncBlock'),你可以把它移动到尽可能接近'Socket'的位置,并且使用Dataflow模块来处理其他事情。 –