在使用 gSoap 链接多个 SOAP 服务时启用保持活动状态



我们有一个执行肥皂方法代理的C++ Windows项目。我们使用 gSoap 来实现输入/服务器服务以通过 SOAP 方法接受数据,以及输出/客户端服务以代理对远程系统的传入调用。

SOAP 服务是在固定的遗留规范中定义的,我们无法控制从中接收数据的客户端系统或将数据代理到的服务器。

SOAP 服务在多个 WSDL 规范中定义,我们的系统必须在一个服务器端口/端点后面实现所有服务。gSoap 文档涵盖了此要求(如何链接C++服务器类以在同一端口上接受消息一节(,我们的代码严格遵循该指南。

总体而言,该系统运行良好,我们有一个独立部署的集成轻量级解决方案。

但是代码部署在一些密集的高容量/高调用频率情况下,这给我们带来了几个问题。我相信如果服务器端服务允许 HTTP keep-alive,我们的问题就会得到解决,但记录的用于链接多个服务的 gSoap 方法特别建议不要启用 HTTP keep-alive:

不要启用保持活动支持,因为套接字可能会保持打开状态 因此,之后无限期

我们已经多次尝试通过启动带有SOAP_IO_KEEPALIVE标志的服务/gSoap来忽略此建议,但是gSoap HTTP连接处理中似乎存在代码,在每个SOAP事务完成后强制关闭连接。

以下是此限制导致的问题类型:

  • 普遍担心在高容量情况下需要为每个唯一事务建立新的 HTTP 连接效率低下。对短暂端口耗尽的担忧。
  • 某些客户端尝试使用 HTTP Expect: 100-continue 调用具有部分数据有效负载的 SOAP 方法。这些事务总是失败,因为连接被 gSoap 服务器关闭,使客户端没有机会继续。
  • 有时需要使用安全的SSL通信。但是,由于没有 HTTP 保持活动状态,客户端需要为每个事务协商一个 SSL 连接,这在高调用频率情况下会带来非常高的开销。

关于我们实施的一些细节: 我们使用 gSoap WSDL2H 组合服务:

wsdl2h -NServTest -s -o ServTestWebServices.h Service1.wsdl Service2.wsdl Service3.wsdl

然后,生成的 gSoap 定义用于实现服务器端服务类:

soapcpp2 -S -j -w -qServTestWSIn -x ServTestWebServices.h

通常,在没有服务链的情况下实现 gSoap 集成 HTTP 连接处理时,代码只是接受连接并调用soap_serve来处理连接的整个生命周期:

struct soap gsoap;
soap_init2(&gsoap, SOAP_IO_KEEPALIVE, SOAP_IO_KEEPALIVE);
SOAP_SOCKET m = soap_bind(gsoap, NULL, port, backlog);
while (soap_valid_socket(soap_accept(gsoap)))
{
soap_serve(gsoap); 
soap_destroy(gsoap); 
soap_end(gsoap);
}

链接多个服务时,soap_serve(( 不起作用,因为它无法将调用定向到正确的服务。而是使用以下方法:

struct soap gsoap;
//SOAP_IO_KEEPALIVE does not help here:
soap_init2(&gsoap, SOAP_IO_KEEPALIVE, SOAP_IO_KEEPALIVE); 
Service1 srv1(gsoap);
Service2 srv2(gsoap);
Service3 srv3(gsoap);
SOAP_SOCKET m = soap_bind(gsoap, NULL, port, backlog);
while (soap_valid_socket(soap_accept(gsoap)))
{
if (soap_begin_serve(gsoap))
soap_stream_fault(gsoap, std::cerr);
else
{
if (srv1.dispatch() == SOAP_NO_METHOD)
if (srv2.dispatch() == SOAP_NO_METHOD)
srv3.dispatch();
if (soap->error)
soap_send_fault(gsoap);
}
}

我意识到这是gSoap系统的一个记录限制,但在我看来,其他人可能遇到过类似的问题。有没有人找到他们可以分享的解决方案/解决方法?

我在这里分享我自己的问题的答案。我最终得到了gSoap人员的一些帮助,他们确认我找到的解决方案应该没有问题。这是我现在使用的代码的要点(基于问题中的代码(:

gsoap->keep_alive = gsoap->max_keep_alive + 1;
do
{
if ((gsoap->keep_alive > 0) && (gsoap->max_keep_alive > 0))
gsoap->keep_alive--;
if (soap_begin_serve(gsoap))
{
if (gsoap->error >= SOAP_STOP)
continue;
else
break;
}
if ((SoapServeResult = srv1.dispatch()) == SOAP_NO_METHOD)
if ((SoapServeResult = srv2.dispatch()) == SOAP_NO_METHOD)
if ((SoapServeResult = srv3.dispatch()) == SOAP_NO_METHOD)
{
//no method found - send fault to client
soap_send_fault(srv3.soap);
}
} while (m_pSoap->keep_alive);

这是Genivia/gSoap支持的回应:

该方法可以确保在以下情况下启用HTTP保持活动状态 运行服务器循环。

文档中的示例是一种简化的方法,用于显示 链接多个尝试调度的逻辑,但它具有 你说的保持活动限制。

但这并不妨碍使用我们用于 未更改的服务调度。您使用的代码很好, 通过调度尝试替换循环主体的要点。

想知道我们是否应该在文档中对此说些什么 限制,因为它没有提到这一点。

最新更新