Manual

do

Maker

.

com

Qt - Servidor XMLRPC utilizando a libMaia

Qt - Servidor XMLRPC utilizando a libMaia

XMLRPC utilizando a libMaia

Por algumas vezes tive que fazer um servidor XMLRPC utilizando a libMaia no 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!

Artigo sugerido: Conexão persistente com QTCPServer

Nome do Autor

Djames Suhanko

Autor do blog "Do bit Ao Byte / Manual do Maker".

Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.