【问题标题】:Loop with async wait operation weirdness带有异步等待操作怪异的循环
【发布时间】:2012-05-13 08:08:00
【问题描述】:

我有以下将客户端传递给 HandleStationClients 的客户端侦听器。 HandleStationClients 的构造函数在其他线程中启动一个带有连接的任务以进行侦听。

下面的代码使用异步函数在主线程上运行。当客户端连接时,下面的等待部分将继续并将客户端传递给新创建的 HandleStationClients 并挂钩事件。 通常在连接事件之后,循环将重新开始并在等待时等待新的连接。 问题是此代码为每个连接循环两次。因此客户端连接,HandleStationClients 将被创建,事件将被挂钩,while 循环再次开始,然后继续运行相同的进程,再次创建新的 HandleStationClients 和事件挂钩。

客户端处理完毕后,等待者不再等待而是继续第二次。事件被触发两次。我不知道怎么了。有人知道吗?

while (true)
{
    counter += 1;

    // Wait for new connection then do rest
    stationsClientSocket = await stationsServerSocket.AcceptTcpClientAsync();

    stationClients.Add(stationsClientSocket, 0);
    Debug.WriteLine("Client toegevoegd " + counter);

    HandleStationClients stationClient = new HandleStationClients(stationsClientSocket);

    stationClient.ConnectionEstabilished += stationClient_ConnectionEstabilished;
    stationClient.ConnectionClosed += stationClient_ConnectionClosed;
    stationClient.NewDataReceived += stationClient_NewDataReceived;
}

HandleClient 看起来像

class HandleStationClients
{
    public HandleStationClients(TcpClient client)
    {
        Task.Factory.StartNew(() => { ProcessConnection(client); });
    }

    #region Event definitions
    public delegate void NewDataReceivedEventHandler(string newData);
    public event NewDataReceivedEventHandler NewDataReceived;

    public delegate void ConnectionClosedEventHandler();
    public event ConnectionClosedEventHandler ConnectionClosed;

    public delegate void ConnectionEstabilishedEventHandler(IPEndPoint endpoint);
    public event ConnectionEstabilishedEventHandler ConnectionEstabilished;
    #endregion

    public async void ProcessConnection(TcpClient stationsClientSocket)
    {
        byte[] message = new byte[1024];
        int bytesRead;

        NetworkStream networkStream = stationsClientSocket.GetStream();

        if (this.ConnectionEstabilished != null)
        {
            this.ConnectionEstabilished((IPEndPoint)stationsClientSocket.Client.RemoteEndPoint);
        }

        while ((true))
        {
            bytesRead = 0;

            try
            {
                bytesRead = await networkStream.ReadAsync(message, 0, 1024);
            }
            catch (Exception ex)
            {
                // some error hapens here catch it                    
                Debug.WriteLine(ex.Message);
                break;
            }

            if (bytesRead == 0)
            {
                //the client has disconnected from the server
                break;
            }

            ASCIIEncoding encoder = new ASCIIEncoding();

            if (this.NewDataReceived != null)
            {
                byte[] buffer = null;

                string incomingMessage = encoder.GetString(message, 0, bytesRead);

                this.NewDataReceived(incomingMessage);
            }
        }
        stationsClientSocket.Close();
        // Fire the disconnect Event
        this.ConnectionClosed();
    }
}

【问题讨论】:

  • 请展示一个简短但完整的程序来演示问题。仅凭这个 sn-p 就很难弄清楚发生了什么。
  • 我同意乔恩的观点。我尝试运行一个简短的控制台应用程序,它运行良好。
  • 我认为将(n 个整个)Task 设为异步方法并没有多大用处。
  • @Shift,那么你应该自己回答这个问题,或者删除它。

标签: c# wpf sockets async-await


【解决方案1】:

在构造函数中启动任务是个坏主意。这意味着在您注册事件处理程序时您的任务正在运行。很有可能有时您不会在需要触发之前注册事件。

您应该做的是等待启动任务,直到事件处理程序都注册完毕。您需要创建一个Start 方法来负责启动任务,并在注册事件后让代码调用它。

更新的类:

class HandleStationClients
{
    // Added a field to store the value until the Start method
    TcpClient _client;

    public HandleStationClients(TcpClient client)
    {
        this._client = client;
        // Moved the line from here...
    }

    public void Start()
    {
        // ...to here.
        Task.Factory.StartNew(() => { ProcessConnection(_client); });
    }

    #region Event definitions
    // ...
    #endregion

    public async void ProcessConnection(TcpClient stationsClientSocket)
    {
        byte[] message = new byte[1024];
        int bytesRead;

        NetworkStream networkStream = stationsClientSocket.GetStream();

        if (this.ConnectionEstabilished != null)
        {
            this.ConnectionEstabilished((IPEndPoint)stationsClientSocket.Client.RemoteEndPoint);
        }

        while ((true))
        {
            bytesRead = 0;

            try
            {
                bytesRead = await networkStream.ReadAsync(message, 0, 1024);
            }
            catch (Exception ex)
            {
                // some error hapens here catch it                    
                Debug.WriteLine(ex.Message);
                break;
            }

            if (bytesRead == 0)
            {
                //the client has disconnected from the server
                break;
            }

            ASCIIEncoding encoder = new ASCIIEncoding();

            if (this.NewDataReceived != null)
            {
                byte[] buffer = null;

                string incomingMessage = encoder.GetString(message, 0, bytesRead);

                this.NewDataReceived(incomingMessage);
            }
        }
        stationsClientSocket.Close();
        // Fire the disconnect Event
        // I added a line to check that ConnectionClosed isn't null
        if (this.ConnectionClosed != null)
        {
            this.ConnectionClosed();
        }
    }
}

那你需要修改调用代码如下。

while (true)
{
    counter += 1;

    // Wait for new connection then do rest
    stationsClientSocket = await stationsServerSocket.AcceptTcpClientAsync();

    stationClients.Add(stationsClientSocket, 0);
    Debug.WriteLine("Client toegevoegd " + counter);

    HandleStationClients stationClient = new HandleStationClients(stationsClientSocket);

    stationClient.ConnectionEstabilished += stationClient_ConnectionEstabilished;
    stationClient.ConnectionClosed += stationClient_ConnectionClosed;
    stationClient.NewDataReceived += stationClient_NewDataReceived;
    // Call Start manually
    stationClient.Start();
}

【讨论】:

    【解决方案2】:

    我将 Task start 从构造函数移到了 Start 方法。问题解决了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-15
      • 2021-12-24
      • 1970-01-01
      • 2020-04-20
      • 2019-07-21
      • 1970-01-01
      • 1970-01-01
      • 2019-07-02
      相关资源
      最近更新 更多