Я только что столкнулся с той же самой проблемой, и я думаю, что у меня есть решение для вас.
Как вы только что сказали, проблема в том, что 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;
}
Вы должны извлечь тело этой функции и заменить ваш старый вызов soap_serve (mySoap) внутри вашего потока (потока, выполняющего запросы и ошибки из-за keep-alive) следующим:
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), именно эти потоки
Я храню каждый из этих контекстов как элемент массива, который находится в главном потоке обработки соединений.
При завершении основного потока обработки соединения (тот, который обслуживает запросы) он пройдет через все мыльные контексты и завершит «ручное» соединение, используя:
for (int i = 0; i < soaps.size(); ++i) {
soaps[i]->fclose(soaps[i]);
}
Это принудительно завершит цикл soap_serve. Это фактически остановит внутренний цикл возле линии 921 stdsoap2.cpp_
r = select((int)soap->socket + 1, &fd, NULL, &fd, &timeout);
Это не самое чистое решение (не нашло более чистого), но оно определенно остановит обслуживание.