2

http-keepaliveを有効にしてマルチスレッドgSOAPサービスを実行しています。クライアントがまだ接続されているときにサービスを正常にシャットダウンするにはどうすればよいですか?

gSoapでも同様の質問がありました:Webサービスアプリケーションを正常にシャットダウンする方法は?、ただし、回答はhttp-keepaliveの側面をカバーしていません。soap-serve関数は、http-keepalive-sessionがクライアントによって閉じられない限り、単純に戻りません。したがって、受け入れられた回答のステップ2は、クライアントが接続を閉じることを決定するまでブロックされます(または、受信タイムアウトが期限切れになりますが、タイムアウトが短いと、ここで目的のhttp-keepalive動作が中断されます)。

gSOAPドキュメントの例にも同じ問題があります。

これまでに試したのは、メインスレッドからのsoap_serve呼び出しでハングしているすべてのsoap structに対してsoap_done()を呼び出して、http-keepaliveを待機している接続を中断することでした。これは、ほとんどの場合機能しますが、まれな条件でクラッシュします(a競合状態かもしれません)、これは私にとって解決策ではありません。

4

2 に答える 2

1

私はちょうど同じ問題に遭遇しました、そして私はあなたのための解決策を持っていると思います。

あなたが今言ったように、問題はgSoapがsoap_serveにぶら下がっているということです。これは、gSOAPが、すべてのキープアライブリクエストの到着を待機する内部ループを生成するか、サーバー側でタイムアウトが発生するために発生します。

私が行ったことは、自動生成されたサービススタブ内のsoap_serve関数を取得することです。元のsoap_serve関数をリストして、サービススタブファイルで見つけられるようにします。

  SOAP_FMAC5 int SOAP_FMAC6 soap_serve(struct soap *soap)
    {
    #ifndef WITH_FASTCGI
        unsigned int k = soap->max_keep_alive;
    #endif

        do
        {
    #ifdef WITH_FASTCGI
            if (FCGI_Accept() < 0)
            {
                soap->error = SOAP_EOF;
                return soap_send_fault(soap);
            }
    #endif

            soap_begin(soap);

    #ifndef WITH_FASTCGI
            if (soap->max_keep_alive > 0 && !--k)
                soap->keep_alive = 0;
    #endif

            if (soap_begin_recv(soap))
            {   if (soap->error < SOAP_STOP)
                {
    #ifdef WITH_FASTCGI
                    soap_send_fault(soap);
    #else 
                    return soap_send_fault(soap);
    #endif
                }
                soap_closesock(soap);

                continue;
            }

            if (soap_envelope_begin_in(soap)
             || soap_recv_header(soap)
             || soap_body_begin_in(soap)
             || soap_serve_request(soap)
             || (soap->fserveloop && soap->fserveloop(soap)))
            {
    #ifdef WITH_FASTCGI
                soap_send_fault(soap);
    #else
                return soap_send_fault(soap);
    #endif
            }

    #ifdef WITH_FASTCGI
            soap_destroy(soap);
            soap_end(soap);
        } while (1);
    #else
        } while (soap->keep_alive);
    #endif
        return SOAP_OK;
    }

この関数の本体を抽出し、スレッド(keep-aliveのために要求とhagnsを実行するスレッド)内の古いsoap_serve(mySoap)呼び出しを次のように置き換える必要があります。

do
    {
        if ( Server::mustShutdown() ) {
            break;
        }

        soap_begin(mySoap);

        // If we reached the max_keep_alive we'll exit
        if (mySoap->max_keep_alive > 0 && !--k)
            mySoap->keep_alive = 0;


        if (soap_begin_recv(mySoap))
        {   if (mySoap->error < SOAP_STOP)
            {
                soap_send_fault(mySoap);
                break;
            }
            soap_closesock(mySoap);

            continue;
        }

        if (soap_envelope_begin_in(mySoap)
         || soap_recv_header(mySoap)
         || soap_body_begin_in(mySoap)
         || soap_serve_request(mySoap)
         || (mySoap->fserveloop && mParm_Soap->fserveloop(mySoap)))
        {
            soap_send_fault(mySoap);
            break;
        }


    } while (mySoap->keep_alive);

次の点に注意してください。

  1. Server :: mustShutdown()は、すべてのスレッドを終了するために(外部で)trueに設定されるフラグとして機能します。サーバーが新しいリクエストを処理するのを停止したい場合、この関数はtrueを返し、ループは終了します。
  2. ifdef、WITH_FASTCGIを削除しましたが、今は面白くありません。
  3. このように接続を閉じると、サーバーに接続されているすべてのクライアントで例外が発生します。たとえば、C#で記述されたクライアントは、「基盤となる接続は、サーバーによって閉じられた状態を維持するために除外されます」をスローします。これは、私たちにとって完全に理にかなっています。

しかし、AudioComplexが指摘したことのおかげで、システムはまだsoap_begin_recvでの要求を待っています。しかし、私にもその解決策があります;)

接続処理プールの各スレッドは、(soap_copyを介して)メインのsoapコンテキストのコピーを作成します。これらのスレッドは
、メインの接続処理スレッドにある配列の要素として、これらの各コンテキストを格納するスレッドです。 。メインの接続処理スレッド(要求を処理するスレッド)を終了すると、すべてのsoapコンテキストを通過し、以下を使用して接続を「手動で」終了します。

for (int i = 0; i < soaps.size(); ++i) {
  soaps[i]->fclose(soaps[i]);
}

これにより、soap_serveループが強制的に終了します。実際には、stdsoap2.cpp_の行921の近くで内部ループを停止します。

r = select((int)soap->socket + 1, &fd, NULL, &fd, &timeout);

これは最もクリーンなソリューションではありませんが(よりクリーンなソリューションは見つかりませんでした)、サービスを確実に停止します。

于 2011-11-09T11:05:17.870 に答える
0

soap_serveのループを変更する必要はありません。サービスの実装でエラーコードを返すだけです。

return Server::mustShutdown() ? SOAP_SVR_FAULT : SOAP_OK;
于 2021-07-28T05:37:16.710 に答える