none
非同期サーバの複数ポート起動 RRS feed

  • 質問

  • 非同期サーバサンプルhttp://msdn.microsoft.com/ja-jp/library/fx6588te(v=VS.80).aspx

    を使用して、ポート番号を複数個割当、起動を試みました。

    なんとか、動作をするレベルまでは可能でしたが、ポートの2番目(ポート1番目のみでは問題ない)にパケット

    を送出時にCPU使用率を見ると100%のまま下がりませんでした(処理は終わっています)

    おそらく、下記コード(抜粋)が原因と思いますが、どのような対策が有効でしょうか?

    コールバックの所に問題があるとは、解りますが。CPU100%ながら、とりあえず動いてはいます。

    デバッグ時にステップ毎に追従しても、全ての処理が終わる寸前までは、CPU負荷に問題はありません。

    Console.Writelineを随所に入れても、どこにも反応が無く、困っています。

     // Bind the socket to the local endpoint and listen for incoming connections.
            try
            {
             
                for (int i = 0; i < max_port; i++)
                {
                    IPsocket[i].ReceiveTimeout = time;
                    IPsocket[i].Blocking = false; // blocking mode = false
                    IPsocket[i].ReceiveTimeout = time;
                   
                    IPsocket[i].Bind(IPendPP[i]);
                    IPsocket[i].Listen(100);
                    }
               
                while (true)
                {

                    // Set the event to nonsignaled state.
                    allDone.Reset();
                  
             
                    for (int i = 0; i < max_port; i++)
                    {
                     IPsocket[i].BeginAccept(new AsyncCallback(AcceptCallback), IPsocket[i]);
                     //ここの割付が問題と思う。 ポートの1番目のみ使用時(通信)は、問題ない。

             }

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

            }

     

     

    2010年7月27日 10:56

回答

  • 気になることをもう一点
    ●AcceptCallback が起きていないリスナーについても BeginAccept を繰り返しています。

    • 回答としてマーク 山本春海 2010年7月29日 0:48
    2010年7月28日 4:41
  • anningo殿

    ●AcceptCallback が起きていないリスナーについても BeginAccept を繰り返しています。

    より、ポート毎の検出機能を加えました。                                                  具体的には、ポート毎にチェック用のbool配列を作成し、AcceptCallback動作時にポート毎のを許可を与え、allDone.Set();にて、BeginAcceptをポート毎に開始してみました。

    ブレークポイントや、Console.Writeline等を入れていましたが、反応しないのですね。

    無事解決しました、ありがとうございました。

    • 回答としてマーク metal_socket 2010年7月28日 9:11
    2010年7月28日 9:11

すべての返信

  • コードの方はよく吟味していませんが、CPU 100% になった段階で、デバッグメニューから停止を選べば、どのあたりで止まっているかは確認できるのではないでしょうか。
    ほかのスレッドの様子も見ながら、ちょっと推測してみてください。

    その他、わかっていることがあればなるべく多く情報を提示しましょう。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年7月27日 13:41
    モデレータ
  • Azulean殿 返信ありがとうございます。

    情報が少ない為、コードを抜粋して、記載します。

    ・症状は、ポート番号を複数設定(ex. 10000,10100,10200)して起動した場合、クライアントから1個目のポート(10000)での通信は、正常(CPUがほぼ0%まで戻る)です。同状態で、クライアントから2個目のポート(10100)への通信を行った所、正常に処理されますが、処理後(データ返信後のコールバック完了時)にCPU100%となります。   

    ポート番号には関係なく、2個目のポートでの通信処理後にCPUは100%となります。

    新たに解った事は、受信処理中にThread.sleepを入れると、受信処理中だけ90%台になる。            また、他のPCで起動させると、2個目のポートでの通信後、数秒で0%近くまで回復するが、通信できなくなる。  他のPCとは、開発PCよりスペック的に劣るものです。(Eee PC)

    また、ご指摘にもあるように、CPU100%になった段階は、処理完了後(SendCallback)です。               デバッグからステップインしていますが、抜けてしまいます。                              IPsocket[i].BeginAccept(new AsyncCallback(AcceptCallback), IPsocket[i]);               にて受信待ちに入っていると思います。

    どこを変更すれば良いのかご指導願います。

    呼び出すクラス
    public partial class TCPserver : Form
     {
     private void Server_on_Click(object sender, EventArgs e)
     {
             //event サーバ起動
            threadEvent = new Thread(new ThreadStart(Server_lisner));
            threadEvent.Start();
     }
     public void Server_lisner()
     {
           AsynchronousServer asc = new AsynchronousServer();
           //受信イベント 
           asc.E_OnRecive_R += new AsynchronousServer.Server_r(on_read_R);
           //サービス起動
           asc.StartListening(ローカルIP,ポート番号配列,ポート番号個数,タイムアウト);
      }
    }
    
    呼び出されるクラス 
    
    public class ServerStateObject {
      // 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 AsynchronousServer
    {
        // EvevntHandler Datarecive Server_R_Data
        public delegate void Server_r(object r, Server_ER_data r_data);
        public event Server_r E_OnRecive_R;
        static private byte[] A_buffer;  //受信データ
        
        //Socket 
        private IPEndPoint[] IPendPP;
        private Socket[] IPsocket;
        
        // Thread signal.
        private static ManualResetEvent allDone = new ManualResetEvent(false);
    
        //クラスのコンストラクタ
        private static AsyncCallback callbackReader;   
        
        public AsynchronousServer()
        {
          //読み込み完了時にCLRから呼ばれるメソド
          callbackReader = new AsyncCallback(this.ReadCallback);  
        }
    
       
      public void StartListening(IPAddress s_ip,INI_Class.Listner_Common_P_Data[] ini_p_data ,int max_port,int time)
      {
        // Data buffer for incoming data.
        byte[] bytes = new Byte[1024];
       
        
        IPendPP = new IPEndPoint[max_port];
        IPsocket = new Socket[max_port];
       
    
        for (int i = 0; i < max_port; i++)
        {
          IPendPP[i] = new IPEndPoint(s_ip, ini_p_data[i].LPort);
       
          // Create a TCP/IP socket.
    
          IPsocket[i] = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp);
        }
        
        // Bind the socket to the local endpoint and listen for incoming connections.
        try
        {
         
          for (int i = 0; i < max_port; i++)
          {
            IPsocket[i].ReceiveTimeout = time;
            IPsocket[i].Blocking = false; // blocking mode = false
            IPsocket[i].ReceiveTimeout = time;       
            IPsocket[i].Bind(IPendPP[i]);
            IPsocket[i].Listen(100);
            
          }
          
          while (true)
          {
    
            // Set the event to nonsignaled state.
            allDone.Reset();
            for (int i = 0; i < max_port; i++)
            {
             IPsocket[i].BeginAccept(new AsyncCallback(AcceptCallback), IPsocket[i]);
            }
            // Wait until a connection is made before continuing.
             allDone.WaitOne();
           }
    
        }
    
      }
    
      private static 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.
          ServerStateObject state = new ServerStateObject();
          state.workSocket = handler;
          handler.BeginReceive(state.buffer, 0, ServerStateObject.BufferSize, 0,
            callbackReader, state); 
        }      
      }
    
      
      private void ReadCallback(IAsyncResult ar)
      {
        try
        {
    
          String content = String.Empty;
          A_buffer = new byte[1024];
          
          ServerStateObject state = (ServerStateObject)ar.AsyncState;
          Socket handler = state.workSocket;
    
          
          // Read data from the client socket. 
          int bytesRead = handler.EndReceive(ar);
          
          
          if (bytesRead > 0)
          {
                  
          Thread.Sleep(1); 
          Byte[] getByte = new byte[bytesRead];
          for (int i = 0; i < bytesRead; i++)
          getByte[i] = state.buffer[i];
          byte[] uniBytes;
          //'S-Jisからユニコードに変換
          uniBytes = Encoding.Convert(ecSjis, ecUni, getByte);
          string orMsg = BitConverter.ToString(getByte);
              
          //streaem test code
          Byte[] sendBytes = Encoding.UTF8.GetBytes(orMsg);
    
          //バイト配列から文字列に変換する
          string strGetText = ecUni.GetString(uniBytes);
         //受信文字を切り出す
                   
         //受信文字を返信する
         Send(handler,getByte);
    
                                
         //相手先を調べる
         EndPoint locat_ip = handler.LocalEndPoint; 
         //イベント処理 IP,データ数,ASCII,Byteデータ通知
         Server_ER_data rr = new Server_ER_data(locat_ip.ToString(), bytesRead, orMsg, strGetText);
         E_OnRecive_R(this, rr);               
    
         }
          else
          {
            // Not all data received. Get more.
            handler.BeginReceive(state.buffer, 0, ServerStateObject.BufferSize, 0,
            new AsyncCallback(ReadCallback), state);       
          }
        }
      }
    
      private static void Send(Socket handler, byte[] buffer)
      {
        try
        {
         handler.BeginSend(buffer, 0, buffer.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.      
          handler.Shutdown(SocketShutdown.Both);
          handler.Close();     
        }
      }  
    }
    
    
    

       

    2010年7月28日 0:33
  • 気になったのは以下の2点です。
    ●最初の質問のリンク先「非同期サーバサンプル」と比べると ReadCallback の処理が大きく異なる。
    ●SendCallback に EndSend がない。
    2010年7月28日 2:01
  • anningo殿 返信ありがとうございます。

    SendCallback内のEndSendは、int型の変数に返しているだけと思い、削除しました。                         また、あっても無くても結果は、同じでした。

     

    2010年7月28日 3:52
  • 気になることをもう一点
    ●AcceptCallback が起きていないリスナーについても BeginAccept を繰り返しています。

    • 回答としてマーク 山本春海 2010年7月29日 0:48
    2010年7月28日 4:41
  • anningo殿

    なるほど、了解ですが、対策が解りません。                                             どのような方法が適切でしょうか?

     

     

    2010年7月28日 5:33
  • 非同期サーバサンプル」のリンク先の例はあまり変えずに
    そのスレッドをポートの数ぶんスタートするのはいかがでしょう。

    • 編集済み anningo 2010年7月28日 6:15 文言修正
    2010年7月28日 6:13
  • anningo殿

    ●AcceptCallback が起きていないリスナーについても BeginAccept を繰り返しています。

    より、ポート毎の検出機能を加えました。                                                  具体的には、ポート毎にチェック用のbool配列を作成し、AcceptCallback動作時にポート毎のを許可を与え、allDone.Set();にて、BeginAcceptをポート毎に開始してみました。

    ブレークポイントや、Console.Writeline等を入れていましたが、反応しないのですね。

    無事解決しました、ありがとうございました。

    • 回答としてマーク metal_socket 2010年7月28日 9:11
    2010年7月28日 9:11