Qt – Servidor XMLRPC utilizando a libMaia

Por algumas vezes tive que fazer um servidor XML/RPC com o Qt. É um processo consideravelmente simples, mas cada vez que o fiz, tive que relembrar alguns passos obrigatórios. Vou descrever aqui um exemplo de servidor em Qt e um client em python.

Baixando a libmaia
A lib pode ser baixada nesse link. Descomprima-a dentro da pasta do projeto. No nosso exemplo, XMLRPCServer. Entre no diretório e compile com os passos:


qmake
make

No arquivo .pro adicione o que estiver diferente disso:

QT += core gui network xml

TARGET = XMLRPCServer
TEMPLATE = app

SOURCES += main.cpp
mainwindow.cpp

HEADERS += mainwindow.h

FORMS += mainwindow.ui

INCLUDEPATH += /path/XMLRPCServer/libmaia
LIBS += /path/XMLRPCServer/libmaia/libmaia.a

Nesse arquivo foi necessário adicionar o xml e o network, além do path da libmaia e a lib.a.

O server se comunica através de sinais. Então, deve criar slots e eles obrigatoriamente devem ser privados. Adiciono um exemplo simples (utilizando a classe default, MainWindow):

– Primeiramente, o include da libmaia, QDebug e QMap:


#include "maiaXmlRpcServer.h"
#include <QMap>
#include <QDebug>

– O slot privado:

private slots:
QString QuestionAnswer(QString QA);

– A libmaia também deve ser privada:

private:
MaiaXmlRpcServer *server;

– Um dicionário para utilizar na resposta do método:

QMap <QString,QString> answerDict;

No construtor do mainwindow.cpp primeiramente criaremos o objeto da libmaia especificando a porta a utilizar (qualquer uma que não esteja em uso por outro serviço):

server = new MaiaXmlRpcServer(9876, this);

Agora, adiciona-se um método para a comunicação remota:

//server->addMethod(MetodoRemoto,objeto,SlotDoObjeto);
server->addMethod("QuestionAnswer",this,"QuestionAnswer");

Nesse caso, dizemos que quando receber um sinal QuestionAnswer deve-se chamar o slot do mesmo objeto chamado QuestionAnswer. O chamada remota não precisa necessariamente ter o mesmo nome do método local, isso foi apenas para simplificar.

Ainda no construtor, deve-se atribuir os valores do dicionário:


//Sim, ha outra maneira de faze-lo. Eu quero desse jeito, ponto.
this->answerDict["pepino"] = "legume";
this->answerDict["laranja"] = "fruta";

A declaração desse método é bastante simples:

//o metodo recebera uma QString
QString MainWindow::QuestionAnswer(QString QA)
{
    //se houver a chave no dicionario, faz um print
    //do valor e o retorna ao solicitante
    if (this->answerDict.contains(QA)){
        qDebug() << this->answerDict.value(QA);
        return this->answerDict[QA];
    }
    //De qualquer modo, deve-se retornar alguma coisa:
    //deve-se fazer o include do QDebug.
    qDebug() << “UNDEFINED!!”;
    return “undefined”;
}

Client em Python

#!/usr/bin/env python


from xmlrpclib import ServerProxy, Error
import time,sys,random,datetime

//acumulador de erros
ERROS = 0

#O endereco do server deve ser passado como argumento
client = ServerProxy(“http://”+sys.argv[1]+”:9876/RPC2″)
print client

#Criacao de um metodo para fazer as perguntas em um loop:

def perguntas(q):
    resposta = client.QuestionAnswer(q)
    print resposta
    if (q == “pepino” and not resposta == “legume”) or (q == “laranja” and not resposta == “fruta”):
    ERROS += 1

for i in range(100):
    perguntas(“pepino”)
    perguntas(“laranja”)
    time.sleep(0.02)

#Ao fim do loop, mostra o resultado do teste:
print “Erros: ” + str(ERROS)

O arquivo chamei de xmlRpcClient.py e sua execução pode ser de duas maneiras:
chmod 755 xmlRpcClient.py&&./xmlRpcClient.py
python xmlRpcClient.py

Coloquei o básico para o entendimento do processo. Esse código tirei do último servidor que fiz para teste de estabilidade, onde incluí outros métodos em ambos os lados (cliente e servidor), com um print do resumo ao final.

Disparando em uma rede interna 25 instâncias do client, cada uma fazendo requisição a 0.02s não houve nenhum erros, tanto no client quanto no server. O server rodou em um desktop core 2 duo 1.6GHZ com 2GB de ram, sendo que durante o processo consumiu ~50% da CPU e menos de 200MB de memória, inclusive gravando as requisições em disco, abrindo e fechando o arquivo a cada requisição (reforço que essa situação foi criada para testes).

A criação de um client também é possível, mas foi mais rápido escreve-lo para teste em python.
Concluo que a libmaia é bastante estável e confiável para a tarefa que se propõe; e recomendo!

Comments

comments

Djames Suhanko

Djames Suhanko é Perito Forense Digital. Já atuou com deployer em sistemas de missão critica em diversos países pelo mundão. Programador Shell, Python, C, C++ e Qt, tendo contato com embarcados ( ora profissionalmente, ora por lazer ) desde 2009.

Deixe uma resposta