C#如何用回调包装事件驱动的代码

时间:2012-06-15 08:32:35

标签: c# multithreading

我正在使用第三方套接字库,尽管这与我的问题有点无关。该库包含一个“Socket”类,其中包含“ConnectAsync”和“WriteAsync”等方法。在调用这些方法之一后,控制立即返回,并且套接字类引发事件以在操作完成时通知,例如, “ConnectCompleted”和“WriteCompleted”。收到数据时,该类还会引发一个事件:“PacketArrived”。

在我的应用中,我想发送数据并等待回复。因为这可能发生在很多地方,所以将上面的套接字类包装在某种帮助程序中是有意义的,它可以为我完成所有这些操作。我也希望它是异步的,因此UI(WPF)在连接/写入/等待回复期间不会冻结,因此辅助方法调用可能看起来像这样: -

SocketHelper.SendData(dataToSend, myCallback);

收到数据时调用“myCallback”。

是线程的新手,我不知道如何编写这个帮助器 - 不知怎的,它需要将各种方法和事件串在一起,即打开连接,等待连接完成,写入数据,等待写入完成,然后等待数据包到达(然后调用提供的回调)。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:2)

Stephen Toub在“Awaiting Socket Operations”中讨论了.NET 4.5的这个主题。通过一些工作,您可以对.NET 4使用相同的技术。

您可以使用任务并行库simplify asynchronous calls而不是使用回调。使用TPL,您可以将所有套接字操作和回调转换为调用操作并处理结果的任务。

使用ContinueWith等方法可以非常轻松地组合任务,只有在第一个任务完成时才能执行链中的下一个任务。

使用线程池中的线程执行任务,因此您不必关心线程。

TPL已经提供了一种从BeginXXX / EndXXX函数或IAsyncResult对象创建任务的方法。如果您的套接字库提供了这些,您可以立即开始使用任务。

要处理事件,可以使用任务并行库中的TaskCompletionSource创建一个任务,该任务将在您调用套接字方法时启动,并仅在引发相应事件时完成。该技术在“Tasks and the Event-based Asynchronous Pattern

中描述

ParallelExtensionsExtras库使用此技术为WebClient, SmtpClient and Ping提供异步方法版本。

使用“任务和EAP”中的代码,您可以为您的Socket类编写扩展方法,如下所示:

public static Task ConnectTask( this Socket socket, object address) 
{ 
    var tcs = CreateSource(address); 
    socket.ConnectCompleted += 
        (sender, e) => TransferCompletion(tcs, e, () => e.Result, null); 
    socket.ConnectAsync(address, tcs); 
    return tcs.Task; 
}

并像这样使用它:

var connectTask=mySocket.ConnectTask(myaddress);
connectTask.ContinueWith(t=> { ... });

.NET 4.5中的事情变得更加容易。 async / await关键字允许您取消ContinueWith调用并编写与其同步版本非常相似的代码。您可以检查“Awaiting Socket Operations”是否有专门针对套接字的扩展名。