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

时间:2018-09-11 14:14:40

标签: c++ windows keep-alive gsoap

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

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

SOAP服务在多个WSDL规范中定义,并且我们的系统必须在一个服务器端口/端点之后实现所有服务。 gSoap文档满足了这一要求(第How to Chain C++ Server Classes to Accept Messages on the Same Port节),我们的代码严格遵循该指南。

总体上,该系统运行良好,并且我们有一个独立部署的集成轻型解决方案。

但是代码被部署在一些密集的高流量/高呼叫频率的情况下,这给我们带来了一些问题。我相信,如果服务器端服务允许HTTP保持活动状态,我们的问题将得到解决,但是已记录的用于链接多个服务的gSoap方法特别建议不要启用HTTP保持活动状态:

  

请勿启用保持活动状态支持,因为套接字可能保持打开状态   结果无限期地结束。

我们已经尝试通过使用SOAP_IO_KEEPALIVE标志启动services / 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系统的文件限制,但是在我看来,其他人可能也遇到过类似的问题。有没有人找到可以共享的解决方案/解决方法?

1 个答案:

答案 0 :(得分:0)

我在这里分享我自己的问题的答案。最终,我从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保持活动的同时   运行服务器循环。

     

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

     

但这不会阻止我们使用与   不变的服务调度。您使用的代码很好,   用调度尝试替换循环主体的要点。

     

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