2012-05-12 119 views
0

我有以下客户端侦听器将客户端传递给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(); 
    } 
} 
+3

请显示一个简短但完整的*程序来说明问题。从这段代码中弄清楚发生了什么真是太难了。 –

+0

我同意乔恩。我试着运行一个简短的控制台应用程序,它做到了这一点,它工作正常 – svick

+0

我添加了HandClient类 – Shift

回答

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(); 
} 
0

我感动的任务开始从构造客场以Start方法。问题解决了。