C# 在C语言中使用异步方法实现消息循环#
我正在制作一个在线通信应用程序,我想异步处理消息。我发现异步等待模式在实现消息循环中很有用 以下是我到目前为止得到的信息:C# 在C语言中使用异步方法实现消息循环#,c#,asynchronous,async-await,message-loop,C#,Asynchronous,Async Await,Message Loop,我正在制作一个在线通信应用程序,我想异步处理消息。我发现异步等待模式在实现消息循环中很有用 以下是我到目前为止得到的信息: CancellationTokenSource cts=new CancellationTokenSource(); //This is used to disconnect the client. public Action<Member> OnNewMember; //Callback field async void NewMemberCallback
CancellationTokenSource cts=new CancellationTokenSource(); //This is used to disconnect the client.
public Action<Member> OnNewMember; //Callback field
async void NewMemberCallback(ConnectionController c, Member m, Stream stream){
//This is called when a connection with a new member is established.
//The class ConnectionController is used to absorb the difference in protocol between TCP and UDP.
MessageLoop(c, m,stream,cts.Token);
if(OnNewMember!=null)OnNewMember(m);
}
async Task MessageLoop(ConnectionController c, Member m, Stream stream, CancellationToken ct){
MemoryStream msgbuffer=new MemoryStream();
MemoryStream buffer2=new MemoryStream();
while(true){
try{
await ReceiveandSplitMessage(stream, msgbuffer,buffer2,ct); //This stops until data is received.
DecodeandProcessMessage(msgbuffer);
catch( ...Exception ex){
//When the client disconnects
c.ClientDisconnected(m);
return;
}
}
}
CancellationTokenSource cts=新的CancellationTokenSource()//这用于断开客户端的连接。
公共行动委员会成员//回调字段
异步void NewMemberCallback(ConnectionController c、成员m、流){
//当与新成员建立连接时,将调用此函数。
//ConnectionController类用于吸收TCP和UDP之间的协议差异。
MessageLoop(c、m、stream、cts.Token);
如果(OnNewMember!=null)OnNewMember(m);
}
异步任务MessageLoop(ConnectionController c、成员m、流、CancellationToken ct){
MemoryStream msgbuffer=新的MemoryStream();
MemoryStream buffer2=新的MemoryStream();
while(true){
试一试{
wait ReceiveandSplitMessage(stream,msgbuffer,buffer2,ct);//在收到数据之前停止此操作。
DecodeandProcessMessage(msgbuffer);
捕获(…异常示例){
//当客户端断开连接时
c、 客户端(m);
返回;
}
}
}
然后我得到一些警告,说在NewMemberCallback中,不等待对MessageLoop的调用。
我实际上不需要等待MessageLoop方法,因为该方法在连接断开之前不会返回。
像这样使用异步被认为是一种好的实践吗?我听说不等待异步方法是不好的,但我也听说我应该消除不必要的等待。或者对于消息循环使用异步模式被认为是不好的吗?如果你不
等待MessageLoop(c,m,stream,cts.Token)
遇到第一个wait
方法时,该方法将立即返回,然后执行该方法的其余部分。这将是一个触发并忘记的场景。UI线程上不会引发异常,因此如果c.ClientDisconnected(m);
抛出它将在后台线程上引发,并导致显式吞并的异常,因为从方法返回的任务
中存储的任何异常都不会被观察到。您可以在@nosratio中找到有关它的更多信息
老实说,这似乎有点不合常规
是否有更好的方法确定客户端是否已断开连接?您将错过任何可能要向用户或日志显示的重要异常。通常,您希望跟踪已启动的任务,以避免再次进入并处理异常。例如:
Task _messageLoopTask = null;
async void NewMemberCallback(ConnectionController c, Member m, Stream stream)
{
if (_messageLoopTask != null)
{
// handle re-entrancy
MessageBox.Show("Already started!");
return;
}
_messageLoopTask = MessageLoop(c, m,stream,cts.Token);
if (OnNewMember!=null) OnNewMember(m);
try
{
await _messageLoopTask;
}
catch (OperationCanceledException ex)
{
// swallow cancelation
}
catch (AggregateException ex)
{
// swallow cancelation
ex.Handle(ex => ex is OperationCanceledException);
}
finally
{
_messageLoopTask = null;
}
}
检查Lucian Wischik的
如果您可以有多个
MessageLoop
实例,那么您就不必担心重新进入,但您仍然希望观察异常情况。您可以同时运行多个MessageLoop
吗?我将为每个与之通信的客户端运行一个MessageLoop,因此将有许多MessageLoop实例在运行。然后将\u messageLoopTask
设为局部变量或维护挂起任务的列表。您可能希望这样的列表在应用程序关闭时检查任务的状态。谢谢。我会试试。谢谢您的回答。我正在考虑将来自TcpClient的NetworkStream直接放入MessageLoop中的stream参数中,所以我想最简单的方法是检查断开连接时抛出的异常。我也可以使用TcpClient.Connected属性,但我不想进行轮询,这对我来说不是很直观,而且在某种程度上也会占用CPU。对此的一个小更正是:如果c.ClientDisconnected(m)抛出它将在后台线程上引发,并导致未处理的异常。它不会导致在后台线程上引发未处理的异常。相反,当MessageLoop
任务被垃圾回收时,它将被隐式吞没,如前所述。