none
FD_CLOSEイベントについて

    質問

  • Windows でwinsockのAPIを用いて非同期のデータ送受信を行なうアプリについて質問です。

    サーバ側でポートをリッスンしているサービスが居らず、クライアントからのconnectが成功していない状況で、クライアントでFD_CLOSEイベントが発生する場合はありますか?

    背景としては、開発中のアプリで再現不可能なエラーが発生しており、そのときの状況からは、接続が成功するはずがない状況にも関わらず、クライアントでFD_CLOSEイベントが発生したように見えており、どのようなことが原因として考えられるのかを知りたいと思っています。

    一時的に何らかの別のアプリがポートをリッスンしていたことなどが原因の可能性としてあるのかも知れないですが、可能性は低いと考えています。

    • 編集済み jo2015 2017年11月28日 6:43
    2017年11月27日 8:58

すべての返信

  • れす付きませんね。
    多分質問の意図がわかりづらいせいだと思われます。
    コードを示すなどして、より具体的な状況をより詳しく説明する必要があると思います。

    以下は回答ではありません、あしからず。
    よくあるサーバーの実装においては
    「1.リスンするスレッド」と、「2.コミュニケーションするスレッド」は別のスレッドを使います。
    少なくとも別の関数内に実装されていると予測できます。
    なぜなら、アクセプトされないソケットにやるべきことなど何もないからです。
    従って文中の「ポートをリッスンしているサービスが居らず、connectが成功していない状況で」
    のスレッドは1.かと思われます。このスレッドで最小限にやるべきことは、accept()の戻り値を監視すことです。
    この場合、FD_CLOSEの出番はないはずだと思うのですが、どうなんでしょう。

    2017年11月28日 2:27
  • コメントありがとうございます。ご指摘のとおり、質問がわかりにくいと思いましたので、書き直してみました。
    2017年11月28日 6:45
  • まだ、コードの状況の説明が不足していると感じます。
    擬似的コードでよいので、手順を示した方がよいでしょう。
    というのも、歴史的経緯などの影響により、Windowsのソケットのコードは、
    色々な実装方法が考えられるからです。

    例えば、自分のサーバーの仕組みを概略的で擬似コードで示すと

    1.リスン対象のソケット(仮にm_Socket_Listenとします)に対して、
     1.1 m_Socket_Listen = socket();
     1.2 res = bind( m_Socket_Listen,・・);
     1.3 res = listen( m_Socket_Listen, SOMAXCONN);
     1.4 アクセプト待ち無限ループ
           while( 1){
             m_Soket_Accepted = accept( m_Socket_Listen,・・);
             if( INVALID_SOCKET==Soket_Accepted){
                // エラー処理
             }
             break;//接続済み
           }
      のようになってます。複数接続しませんので、1.4はスレッド内で接続次第終了します。
        最終的に m_Soket_Accepted がクライアントがコネクトしたソケットですね。

    2.コミュニケーションはm_Soket_Acceptedに対して処理するスレッドで
       (まず、1.4のスレッドがシグナル化するのを待ちます。)
       HANDLE EventAry[2]
       EventAry[0]=WSACreateEvent(); // イベント作成
       EventAry[1]=ex_Event_EmgStop; // 外部強制停止イベント
       WSAEventSelect( m_Soket_Accepted, EventAry[ 0], FD_READ | FD_CLOSE); // 受信/切断を検知
       while( true == m_Run){
          res = WSAWaitForMultipleEvents( 2, EventAry, FALSE, WSA_INFINITE, FALSE);// イベント発生待ち
          if( res == WSA_WAIT_FAILED){ // イベント待ち失敗終了}
          long EventNo = res - WSA_WAIT_EVENT_0;
          switch( EventNo){
          case 0: // 受信又は切断
             WSAEnumNetworkEvents( m_Soket_Accepted, EventAry[ EventNo], &SCK_Event);
             if( SCK_Event.lNetworkEvents & FD_CLOSE){// ★
                 // 切断処理
             }
             else if( SCK_Event.lNetworkEvents & FD_READ){
               // 受信処理
             }
             WSAResetEvent();  // イベントのリセット
             break;
          case 1:{
             //外部強制停止イベント
          }
          }
       }
       // イベントの破棄
       // ソケットの破棄

    といった感じです。
    FD_CLOSEは★の場所にあり、m_Soket_Acceptedが有効にならない限り呼ばれませんし、
    コミュニケーションスレッドは、アクセプトを監視しているスレッドがシグナルになるのを
    待っているのでメインの受信無限ループには到達しない仕組みになってます。

    結局はどのようなコードかを示さないと、有効な意見は得られないと予測できます。


    2017年11月28日 7:55