FromAsync BeginReceive冻结WinForm

时间:2012-03-03 13:13:26

标签: c# c#-4.0

它在控制台应用程序中运行良好,但是当我创建WinForm时,它会冻结我的表单。

我实际上知道,为什么会发生:

public static Task<int> ReceiveAsync(this Socket socket, byte[] buffer, int offset, int size, SocketFlags flags = SocketFlags.None)
{
    if (socket == null) throw new Exception("Socket is null.");
        var tcs = new TaskCompletionSource<int>(socket);
        socket.BeginReceive(buffer, offset, size, flags, iar =>
        {
            var t = (TaskCompletionSource<int>)iar.AsyncState;
            var s = (Socket)t.Task.AsyncState;
            try { t.SetResult(s.EndReceive(iar)); }
            catch (Exception exc) { t.SetException(exc); }
        }, tcs);
        return tcs.Task;
    }

while ((byteRead = ReceiveAsync(socket, buffer, 0, buffer.Length, SocketFlags.None).Result) > 0)
{
   lock (buffer)
   {
       try
       {
          byte[] dBuffer = decompressor.Decompress(buffer);
          lock (dBuffer)
          {
              string receivedData = Encoding.UTF8.GetString(dBuffer);
              OnRead(receivedData, byteRead);
          }
       }
       catch (Exception ex)
       {
          Client.Base.Log.Save(ex);
          socket.Shutdown(SocketShutdown.Both);
       }
   }
}

我认为,在单独的线程中启动ReceiveAsync-Task方法不是一个好主意。

我可以使用没有while循环的FormAsync,如Async-Methods(BeginXXX,EndXXX)吗?

提前致谢!

1 个答案:

答案 0 :(得分:0)

看起来您需要在单独的线程中调用第二个代码段。否则,第二个代码片段只会强制从第一个代码段的异步调用同步工作(这就是让你的WindowsForms应用程序挂起的原因 - 只需调用你在单独的线程中发布的整个代码的第二部分,它就可以了。)

修改

为避免挂起应用程序,可以稍微更改您使用的功能的定义 - 如下所示:

    // Is not changed
    public static Task<int> ReceiveAsync(this Socket socket, byte[] buffer, int offset, int size, SocketFlags flags = SocketFlags.None)
    {

        if (socket == null) throw new Exception("Socket is null.");

        var tcs = new TaskCompletionSource<int>(socket);
        socket.BeginReceive(buffer, offset, size, flags, iar =>
        {
            var t = (TaskCompletionSource<int>)iar.AsyncState;
            var s = (Socket)t.Task.AsyncState;
            try { t.SetResult(s.EndReceive(iar)); }
            catch (Exception exc) { t.SetException(exc); }
        }, tcs);
        return tcs.Task;
    }

    // Moved to new function
    public void PerformRead()
    {
        while ((byteRead = ReceiveAsync(socket, buffer, 0, buffer.Length, SocketFlags.None).Result) > 0)
        {
           lock (buffer)
           {
               try
               {
                  byte[] dBuffer = decompressor.Decompress(buffer);
                  lock (dBuffer)
                  {
                      string receivedData = Encoding.UTF8.GetString(dBuffer);
                      OnRead(receivedData, byteRead);
                  }
               }
               catch (Exception ex)
               {
                  Client.Base.Log.Save(ex);
                  socket.Shutdown(SocketShutdown.Both);
               }
           }
        }
    }

然后,当您以下列方式调用读取套接字时,您的应用程序将顺利运行(没有延迟):

// Invokes reading of socket in separate thread
Thread readSocketThread = new Thread(this.PerformRead);
readSocketThread.Start();

注意:您必须以某种方式将读取的数据传送到Windows窗体控件(例如,通过某些字段或属性或直接从读取套接字的线程访问窗体的字段)。 / p>