我刚刚遇到了同样的问题,我想我已经为你找到了解决方案。
正如您刚才所说,问题在于 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) 调用:
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 上的reqeuests。但我也有解决方案;)
连接处理池上的每个线程都创建主soap上下文的副本(通过soap_copy),这些线程是
我将这些上下文中的每一个存储为驻留在主连接处理线程上的数组上的元素的线程. 当终止主连接处理线程(为请求提供服务的线程)时,它将遍历所有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);
这不是最干净的解决方案(还没有找到更干净的解决方案),但它肯定会停止服务。