我正在为网络应用程序协议开发客户端库。
客户端代码调用库来初始化它并连接到服务器。 客户端当然可以向服务器发送请求,但服务器也可以向客户端发送请求(命令,下面称为Cmd)。
传输协议是TCP / IP,因此基本上客户端库连接到服务器并调用异步方法以从服务器检索下一个请求或响应,以避免在等待响应时阻止I / O阻塞/来自服务器的请求。
话虽如此,我在库中看到了两种可能的解决方案(仅使用C#构造,没有特定的第三方框架),以允许客户端从服务器接收请求:
在库中提供事件,例如
public EventHandler<ReceivedCmdEventArgs> event ReceivedCmd;
客户端将订阅,以便了解从服务器传入的请求。 当然对于这种机制,我将不得不在客户端库中创建一个异步循环来接收来自服务器的请求并在Cmd接收时引发事件。
或者另一种解决方案是在客户端库中创建这样的方法
public async Task<Cmd> GetNextCmdAsync()
客户端代码将在异步循环中调用以接收cmds。
这些解决方案是否相同?是否更好地完全使用C#5的async / await constrcuts而不再依赖于事件?有什么区别 ?任何建议,评论?
谢谢!
答案 0 :(得分:4)
Task
表示单个异步操作,例如接收单个命令。因此,it is not directly suitable for streams of events。
事件流的终极库是Reactive Extensions (Rx),但遗憾的是它有一个相当陡峭的学习曲线。
较新的选项是鲜为人知的TPL Dataflow,它允许构建async
友好的数据流网格。实际上,我正在编写一个async
友好的TCP / IP套接字包装器,我将ISourceBlock<ArraySegment<byte>>
作为读取流。然后,最终用户可以直接从该块接收(ReceiveAsync
),或者他们可以将其“链接”到他们自己的数据流中(例如,可以进行消息成帧,解析甚至处理)。
数据流的效率略低于Rx,但我认为较低的学习曲线是值得的。
我不推荐裸事件 - 你要么最终得到一个自由线程事件(考虑如何处理套接字关闭 - 可能在事件发生之后发生事件?)或基于事件的异步模式(它有它的拥有与提供的SynchronizationContext
)同步的类似问题。 Rx和Dataflow都为同步和处理/取消订阅提供了更好的解决方案。
答案 1 :(得分:2)
我认为事件驱动的方法在你的情况下更好。
事实上,你在谈论一个可观察/观察者模式。 如果收到某些命令,未知数量的侦听器/观察者正在等待做某事。
Async / await模式不能像事件驱动方法一样工作,因为它类似我希望一个结果与相反我会做你想做的事情每当您报告我收到命令时。
从概念上讲,我更喜欢事件驱动的方法,因为它更符合您的架构目标。
C#5中的异步/等待模式不是针对您的情况而设计的,而是针对某些代码执行异步任务以及下一代码行应在任务收到结果后执行的情况。
答案 2 :(得分:0)
由于您正在创建一个库,事件似乎更适合。
事件允许您构建库而不强制必须指定回调。
图书馆的消费者决定他们感兴趣的内容,并倾听这些事件。
另一方面,异步任务意味着您将知道存在延迟(IO,网络等)。异步任务允许您在发生这些延迟时释放资源,从而更好地利用资源。
异步任务不能替代您引发的事件。