2017-01-27 33 views
0

私は、異なる子フォームを接続するためにC#クラスを使用します。 プロジェクトはMDIタイプです。 接続フォームには、スレッドによって呼び出される非同期ソケット・リスナーがあります。 アプリケーションを閉じると、リスナーを閉じることができず、プログラムはタスクマネージャに残ります。 問題は開いているリスナーにリンクしています。私はこのコードを形成し、接続して使用してくださいません別のスレッドで非同期ソケットリスナを正しく閉じるにはどうすればいいですか?

private void hideMonBt_Click(object sender, EventArgs e) 
    { 
     this.Hide(); 
     m_engMonitor.m_masterConn.StopThr(); // Stop "server" 
    } 

    private void c_frmMonitor_Load(object sender, EventArgs e) 
    { 
     m_engMonitor.socketConnect(); // Start "server" connection 
    } 

:フォームの子で

private AsynchronousSocketListener socketListener;   // Per socket in ascolto da parte delle App to Machine 
    private Thread t_listener; 

    public c_masterConn() //Costructor 
    { 
     socketListener = new AsynchronousSocketListener();   // Socketlistner async 
     t_listener = new Thread(socketListener.StartListening);  // Thread for socketlistener 
     t_listener.Start();           // Start socketlistener 
    } 

    public void StopThr() //Stop listner thread 
    { 
     t_listener.Interrupt(); 
    } 

    public class AsynchronousSocketListener 
    { 
     // Thread signal. 
     public static ManualResetEvent allDone = new ManualResetEvent(false); 

     public AsynchronousSocketListener() 
     { 
     } 

     public void StartListening() 
     { 
      // Data buffer for incoming data. 
      byte[] bytes = new Byte[1024]; 

      // Establish the local endpoint for the socket. 
      // The DNS name of the computer 
      // running the listener is "host.contoso.com". 
      IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName()); 
      IPAddress ipAddress = ipHostInfo.AddressList[0]; 
      IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000); 

      // Create a TCP/IP socket. 
      Socket listener = new Socket(AddressFamily.InterNetwork, 
       SocketType.Stream, ProtocolType.Tcp); 

      // Bind the socket to the local endpoint and listen for incoming connections. 
      try 
      { 
       listener.Bind(localEndPoint); 
       listener.Listen(100); 

       while (true) 
       { 
        // Set the event to nonsignaled state. 
        allDone.Reset(); 

        // Start an asynchronous socket to listen for connections. 
        //Console.WriteLine("Waiting for a connection..."); 
        listener.BeginAccept(
         new AsyncCallback(AcceptCallback), 
         listener); 

        // Wait until a connection is made before continuing. 
        allDone.WaitOne(); 
       } 

      } 
      catch (Exception e) 
      { 
       //Console.WriteLine(e.ToString()); 
      } 

      //Console.WriteLine("\nPress ENTER to continue..."); 
      //Console.Read(); 

     } 

     public static void AcceptCallback(IAsyncResult ar) 
     { 
      // Signal the main thread to continue. 
      allDone.Set(); 

      // Get the socket that handles the client request. 
      Socket listener = (Socket)ar.AsyncState; 
      Socket handler = listener.EndAccept(ar); 

      // Create the state object. 
      StateObject state = new StateObject(); 
      state.workSocket = handler; 
      handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
       new AsyncCallback(ReadCallback), state); 
     } 

     public static void ReadCallback(IAsyncResult ar) 
     { 
      String content = String.Empty; 

      // Retrieve the state object and the handler socket 
      // from the asynchronous state object. 
      StateObject state = (StateObject)ar.AsyncState; 
      Socket handler = state.workSocket; 

      // Read data from the client socket. 
      int bytesRead = handler.EndReceive(ar); 

      if (bytesRead > 0) 
      { 
       // There might be more data, so store the data received so far. 
       state.sb.Append(Encoding.ASCII.GetString(
        state.buffer, 0, bytesRead)); 

       // Check for end-of-file tag. If it is not there, read 
       // more data. 
       content = state.sb.ToString(); 
       if (content.IndexOf("<EOF>") > -1) 
       { 
        // All the data has been read from the 
        // client. Display it on the console. 
        //Console.WriteLine("Read {0} bytes from socket. \n Data : {1}", 
        // content.Length, content); 
        // Echo the data back to the client. 
        Send(handler, content); 
       } 
       else 
       { 
        // Not all data received. Get more. 
        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
        new AsyncCallback(ReadCallback), state); 
       } 
      } 
     } 

     private static void Send(Socket handler, String data) 
     { 
      // Convert the string data to byte data using ASCII encoding. 
      byte[] byteData = Encoding.ASCII.GetBytes(data); 

      // Begin sending the data to the remote device. 
      handler.BeginSend(byteData, 0, byteData.Length, 0, 
       new AsyncCallback(SendCallback), handler); 
     } 

     private static void SendCallback(IAsyncResult ar) 
     { 
      try 
      { 
       // Retrieve the socket from the state object. 
       Socket handler = (Socket)ar.AsyncState; 

       // Complete sending the data to the remote device. 
       int bytesSent = handler.EndSend(ar); 
       //Console.WriteLine("Sent {0} bytes to client.", bytesSent); 

       handler.Shutdown(SocketShutdown.Both); 
       handler.Close(); 

      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.ToString()); 
      } 
     } 
     public void StopListening() // Stop Listening 
     { 
      allDone.Close(); 
     } 
    } 

私はこれを置く:このコードを置く形接続では

public void StopListening() // Stop Listening 
     { 
      allDone.Close(); 
     } 

public void StopThr() //Stop listner thread 
    { 
     t_listener.Interrupt(); 
    } 

何私は間違っている?ありがとう。

+0

リスナー(サーバー)はクライアントのスレーブであり、決して閉鎖を開始すべきではありません。コマンドはクライアントから来るべきです。したがって、アプリケーションネットワークレベルのクライアントは、サーバーにクローズメッセージを送信する必要があります。サーバは、接続を終了する準備ができたら、接続を閉じて、クライアントにACKを返すように準備する必要があります。次に、クライアントは接続を閉じる必要があります。サーバーはBeginDisconnectイベントを待機する必要があります。あなたがBeginDisconnectを聞くだけでなく、アプリケーション層を持っていないなら。 – jdweng

+0

@Jitendra Aanadani - これは、Webソケットではなく、単純なTCPソケットです。 –

+0

答えに感謝します。私が父の形を閉じると、子供はこれを行うことができますか? Damien_The_Unbelieverありがとう、私は正しいタグを入れた;-) – Tarma

答えて

0

問題は、リスニングを止めることがないということです。あなたは無限ループであなたのソケットを走らせています。そして、あなたがそれを終了させたいときにあなたはソケットを閉じていませんが、あなたはスレッドを中断しています。それはあなたのドアを開け、あなたの後ろで閉じるのではなく、あなたのドアをノックすることによってあなたの家を離れるのと同じです。

リスニングを正しく停止するには、ソケットを閉じます。この場合、BeginAcceptObjectDisposedExceptionを投げます。あなたは、リスナーを終了したい場合は、単にStopListeningを呼び出す

public class AsynchronousSocketListener : IDisposable 
{ 
    Socket listener; 
    // Thread signal. 
    public ManualResetEvent allDone = new ManualResetEvent(false); 

    public AsynchronousSocketListener() 
    { 
    } 

    public void StartListening() 
    { 
     // Data buffer for incoming data. 
     byte[] bytes = new Byte[1024]; 

     // Establish the local endpoint for the socket. 
     // The DNS name of the computer 
     // running the listener is "host.contoso.com". 
     IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName()); 
     IPAddress ipAddress = ipHostInfo.AddressList[0]; 
     IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000); 

     // Create a TCP/IP socket. 
     listener = new Socket(AddressFamily.InterNetwork, 
      SocketType.Stream, ProtocolType.Tcp); 

     // Bind the socket to the local endpoint and listen for incoming connections. 
     try 
     { 
      listener.Bind(localEndPoint); 
      listener.Listen(100); 

      while (true) 
      { 
       // Set the event to nonsignaled state. 
       allDone.Reset(); 

       // Start an asynchronous socket to listen for connections. 
       //Console.WriteLine("Waiting for a connection..."); 
       listener.BeginAccept(
        new AsyncCallback(AcceptCallback), 
        listener); 

       // Wait until a connection is made before continuing. 
       allDone.WaitOne(); 
      } 

     } 
     catch (ObjectDisposedException) 
     { 
      //Console.WriteLine("Listener closed."); 
     } 
     catch (Exception e) 
     { 
      //Console.WriteLine(e.ToString()); 
     } 

     //Console.WriteLine("\nPress ENTER to continue..."); 
     //Console.Read(); 

    } 

    //... 

    public void StopListening() // Stop Listening 
    { 
     Socket exListener = Interlocked.Exchange(ref listener, null); 
     if (exListener != null) 
     { 
      exListener.Close(); 
     } 
    } 

    public void Dispose() 
    { 
     StopListening(); 
    } 
} 

:あなたのスレッドを中断するすべての必要はありません。 StartListeningが終了すると、スレッドは正常に終了します。

私はあなたのコードに行われたいくつかのその他の変更:

  • 私はAsynchronousSocketListenerが使い捨てました。あなたはソケットをラッピングしているので、リスナーが処分されたときに解放されていることを確認する必要があります。
  • allDonestaticからインスタンスに変更しました。複数のリスナー(複数のポートなど)がある場合は、イベントを共有することになり、これがバグです。

あなたはまだやるに必要なもの:StartListeninglistenerの値を割り当てている前に、あなたがStopListeningを呼び出すと、リスニングは停止しません。リスナーは正常に起動します。これは、コード内の競合状態であり、排除する必要があります。

+0

解決に感謝します。私は少し問題があります。私はアプリケーションをデバッグモードで起動し、ステップコードはdispose関数に入りません。何が問題ですか? – Tarma

+0

disposeメソッドを明示的に呼び出さないと、それがまったく呼び出されないという保証はありません。ガーベジコレクターはそれを呼び出すかもしれませんが、あなたはいつか分かりません。 – Sefe

0

私は、このモードでの問題解決:

class c_masterConn 
{ 

    private AsynchronousSocketListener socketListener;    // socketlistner 
    private Thread t_listener; 

    public c_masterConn()           //Costructor 
    { 
     socketListener = new AsynchronousSocketListener();   // Socketlistner async 
     t_listener = new Thread(socketListener.StartListening);  // Thread for socketlistener 
     t_listener.Start();           // Start socketlistener 

    } 

    public void StopConnection() 
    { 
     socketListener.StopListening(); 
    } 

    // State object for reading client data asynchronously 
    public class StateObject 
    { 
     // Client socket. 
     public Socket workSocket = null; 
     // Size of receive buffer. 
     public const int BufferSize = 1024; 
     // Receive buffer. 
     public byte[] buffer = new byte[BufferSize]; 
     // Received data string. 
     public StringBuilder sb = new StringBuilder(); 
    } 


    public class AsynchronousSocketListener 
    { 
     Socket listener; 
     // Thread signal. 
     public ManualResetEvent allDone = new ManualResetEvent(false); 

     public AsynchronousSocketListener() 
     { 
     } 

     public void AcceptCallback(IAsyncResult ar) 
     { 
      try 
      { // Signal the main thread to continue. 
       allDone.Set(); 

       // Get the socket that handles the client request. 
       Socket listener = (Socket)ar.AsyncState; 
       Socket handler = listener.EndAccept(ar); 

       // Create the state object. 
       StateObject state = new StateObject(); 
       state.workSocket = handler; 
       handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
        new AsyncCallback(ReadCallback), state); 
      } 
      catch (Exception ex) 
      { } 
     } 

     public static void ReadCallback(IAsyncResult ar) 
     { 
      String content = String.Empty; 

      // Retrieve the state object and the handler socket 
      // from the asynchronous state object. 
      StateObject state = (StateObject)ar.AsyncState; 
      Socket handler = state.workSocket; 

      // Read data from the client socket. 
      int bytesRead = handler.EndReceive(ar); 

      if (bytesRead > 0) 
      { 
       // There might be more data, so store the data received so far. 
       state.sb.Append(Encoding.ASCII.GetString(
        state.buffer, 0, bytesRead)); 

       // Check for end-of-file tag. If it is not there, read 
       // more data. 
       content = state.sb.ToString(); 
       if (content.IndexOf("<EOF>") > -1) 
       { 
        // All the data has been read from the 
        // client. Display it on the console. 
        //Console.WriteLine("Read {0} bytes from socket. \n Data : {1}", 
        // content.Length, content); 
        // Echo the data back to the client. 
        Send(handler, content); 
       } 
       else 
       { 
        // Not all data received. Get more. 
        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
        new AsyncCallback(ReadCallback), state); 
       } 
      } 
     } 

     private static void Send(Socket handler, String data) 
     { 
      // Convert the string data to byte data using ASCII encoding. 
      byte[] byteData = Encoding.ASCII.GetBytes(data); 

      // Begin sending the data to the remote device. 
      handler.BeginSend(byteData, 0, byteData.Length, 0, 
       new AsyncCallback(SendCallback), handler); 
     } 

     private static void SendCallback(IAsyncResult ar) 
     { 
      try 
      { 
       // Retrieve the socket from the state object. 
       Socket handler = (Socket)ar.AsyncState; 

       // Complete sending the data to the remote device. 
       int bytesSent = handler.EndSend(ar); 
       //Console.WriteLine("Sent {0} bytes to client.", bytesSent); 

       handler.Shutdown(SocketShutdown.Both); 
       handler.Close(); 

      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.ToString()); 
      } 
     } 



     public void StartListening() 
     { 
      // Data buffer for incoming data. 
      byte[] bytes = new Byte[1024]; 

      // Establish the local endpoint for the socket. 
      // The DNS name of the computer 
      // running the listener is "host.contoso.com". 
      IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName()); 
      IPAddress ipAddress = ipHostInfo.AddressList[0]; 
      IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000); 

      // Create a TCP/IP socket. 
      listener = new Socket(AddressFamily.InterNetwork, 
       SocketType.Stream, ProtocolType.Tcp); 

      // Bind the socket to the local endpoint and listen for incoming connections. 
      try 
      { 
       listener.Bind(localEndPoint); 
       listener.Listen(100); 

       while (true) 
       { 
        // Set the event to nonsignaled state. 
        allDone.Reset(); 

        // Start an asynchronous socket to listen for connections. 
        //Console.WriteLine("Waiting for a connection..."); 
        listener.BeginAccept(
             new AsyncCallback(AcceptCallback), 
             listener); 

        // Wait until a connection is made before continuing. 
        allDone.WaitOne(); 
       } 

      } 
      catch (ObjectDisposedException) 
      { 
       //Console.WriteLine("Listener closed."); 
      } 
      catch (Exception e) 
      { 
       //Console.WriteLine(e.ToString()); 
      } 

      //Console.WriteLine("\nPress ENTER to continue..."); 
      //Console.Read(); 

     } 

     //... 

     public void StopListening() // Stop Listening 
     { 
      Socket exListener = Interlocked.Exchange(ref listener, null); 
      if (exListener != null) 
      { 
       exListener.Close(); 
      } 
     } 
    } 

私はSEFEのソリューションを使用しますが、機能「処分」が呼び出されたときに、私は変更を。 私は、父のフォームの "Form_close"イベントでStopListening関数を呼び出します。 このモードでは、アプリケーションが正しく閉じます。

関連する問題