私はちょうど同じ問題に遭遇しました、そして私はあなたのための解決策を持っていると思います。
あなたが今言ったように、問題は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);
次の点に注意してください。
- Server :: mustShutdown()は、すべてのスレッドを終了するために(外部で)trueに設定されるフラグとして機能します。サーバーが新しいリクエストを処理するのを停止したい場合、この関数はtrueを返し、ループは終了します。
- ifdef、WITH_FASTCGIを削除しましたが、今は面白くありません。
- このように接続を閉じると、サーバーに接続されているすべてのクライアントで例外が発生します。たとえば、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);
これは最もクリーンなソリューションではありませんが(よりクリーンなソリューションは見つかりませんでした)、サービスを確実に停止します。