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

Enabling keep-alive when chaining multiple SOAP services with gSoap

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

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

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

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

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

Do not enable keep-alive support, as the socket may stay open indefinitely afterwards as a consequence.

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

这些是此限制导致的问题类型:

关于我们实施的一些细节: 我们使用 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 支持的回复:

The approach is fine to make sure HTTP keep-alive is enabled while running the server loop.

The example in the documentation is a simplified approach to show the logic of chaining multiple attempted dispatches, but it has the keep-alive limitation you stated.

But that does not prevent the use of the same strategy we use for a non-changed service dispatching. The code you are using is fine, replacing the gist of the loop body by the dispatch attempts.

Wondering if we should say something in the documentation about this limitation, since it does not mention this.