6

我正在为网络应用程序协议开发客户端库。

客户端代码调用库来初始化它并连接到服务器。客户端当然可以向服务器发送请求,但是服务器也可以向客户端发送请求(Commands,下面称为Cmd)。

传输协议是 TCP/IP,所以基本上客户端库连接到服务器并调用异步方法以从服务器检索下一个请求或响应,以避免在等待来自的响应/请求时 I/O 阻塞服务器。

话虽如此,我在库中看到了两种可能的解决方案(仅使用 C# 构造,没有特定的第三方框架),以允许客户端接收来自服务器的请求:

要么在图书馆提供活动,例如

public EventHandler<ReceivedCmdEventArgs> event ReceivedCmd;

客户端将订阅,以便收到来自服务器的请求的通知。当然,对于这种机制,我必须在客户端库中创建一个异步循环来接收来自服务器的请求并在 Cmd 接收时引发事件。

或者另一种解决方案是在客户端库中制作这样的方法

public async Task<Cmd> GetNextCmdAsync()

客户端代码将在异步循环中调用以接收 cmd。

这些解决方案是否相同?完全使用 C#5 的 async/await 构造而不依赖事件会更好吗?有什么区别 ?有什么建议,备注?

谢谢 !

4

3 回答 3

4

Task表示单个异步操作,例如接收单个命令。因此,它并不直接适用于事件流

事件流的终极库是Reactive Extensions (Rx),但不幸的是它的学习曲线相当陡峭。

一个较新的选项是鲜为人知的TPL Dataflow,它允许构建async友好的数据流网格。事实上,我正在编写一个async友好的 TCP/IP 套接字包装器,并且ISourceBlock<ArraySegment<byte>>作为读取流公开。然后,最终用户可以直接从该块接收ReceiveAsync

Dataflow 的效率略低于 Rx,但我认为较低的学习曲线是值得的。

我不会推荐一个裸事件——你要么最终得到一个自由线程事件(想想你将如何处理套接字关闭 - 处理后会发生事件吗?)或者基于事件的异步模式(它有自己类似的问题同步到提供的SynchronizationContext)。Rx 和 Dataflow 都为同步和处置/取消订阅提供了更好的解决方案。

于 2012-08-20T12:37:06.563 回答
3

我认为事件驱动的方法在你的情况下更好。

实际上,您正在谈论可观察/观察者模式。如果收到某个命令,未知数量的侦听器/观察者正在等待执行某项操作。

Async/await 模式不会像事件驱动的方法那样工作,因为它就像我期望一个结果相反,每当你向我报告你收到命令时我会做你想做的事

从概念上讲,我更喜欢事件驱动的方法,因为它更适合您的架构目标。

C# 5 中的异步/等待模式不是为您的情况设计的,但它适用于某些代码执行异步任务并且应在任务收到结果后执行下一行代码时。

于 2012-08-20T10:53:01.890 回答
0

由于您正在制作图书馆,因此事件似乎更适合。

事件允许您在不强制必须指定回调的情况下构建库。

您图书馆的消费者决定他们感兴趣的内容并收听这些事件。

另一方面,异步任务意味着您知道会有延迟(IO、网络等)。异步任务允许您在这些延迟发生时释放资源,从而更好地利用资源。

异步任务不能替代您引发的事件。

于 2012-08-20T10:52:12.150 回答