C++ Qt:创建一个库来连接到外部资源,并在不同的应用程序中使用它
我试图实现一个库来连接到外部资源,并通过基于XML的API与之交互。然而,我不知道如何在处理之前获取所有数据。我正在Windows上使用QTcpSocket 我与资源互动的方式如下:C++ Qt:创建一个库来连接到外部资源,并在不同的应用程序中使用它,c++,qt,qtcpsocket,C++,Qt,Qtcpsocket,我试图实现一个库来连接到外部资源,并通过基于XML的API与之交互。然而,我不知道如何在处理之前获取所有数据。我正在Windows上使用QTcpSocket 我与资源互动的方式如下: 连接到服务器 发送带有凭据的XML消息 从服务器获取响应 解析XML响应以提取会话ID 用包含会话ID的XML发送其他请求,并解析XML响应 在我的应用程序中使用结果 当然,根据请求,消息将不会具有相同的结构,因此我需要在相同的函数中解析XML,对吗?如果是这样的话,我怎么能等到所有数据到达后再对其进行解析呢 此外
#include "client.h"
#include <pugixml.hpp>
#include <map>
#include <sstream>
#include <string>
#include "task.h" // Generate the API message, not relevant
Client::Client(const QString& server, const QString& port, QObject* parent):
QObject(parent)
{
connectToServer(server, port);
connect(&socket_, &QTcpSocket::readyRead, this, &Client::getResult);
}
void Client::connectToServer(const QString& server, const QString& port)
{
bool ok;
int portNumber = port.toInt(&ok);
if (ok) {
if (socket_.state() == QTcpSocket::SocketState::ConnectedState)
socket_.disconnectFromHost();
socket_.connectToHost(server, portNumber);
} else {
throw tr("Cannot connect to server %1 on port %2. Make sure the provided information are correct.")
.arg(server)
.arg(port);
}
}
void Client::throwOnError(const pugi::xml_document& doc)
{
pugi::xpath_node_set errors = doc.select_nodes("/EXECUTION/TASK/RESULTSET/RESULT/MESSAGE");
std::string error_message = "";
for (pugi::xpath_node_set::const_iterator it = errors.begin(); it != errors.end(); ++it)
{
pugi::xml_node node = it->node();
if (std::string(node.attribute("type").value()) == "Error" ||
std::string(node.attribute("type").value()) == "Warning")
error_message += node.child_value();
}
if (!error_message.empty())
throw std::exception(error_message.c_str());
}
void Client::sendMessage(const QString &message)
{
outMessage = message;
result_.clear();
socket_.write(message.toUtf8());
}
void Client::getResult()
{
emit startReading();
while (socket_.bytesAvailable() > 0) {
result_.append(socket_.readAll());
socket_.flush();
}
resultMessage = QString(result_);
emit finishedReading();
}
void Client::login(const QString& user, const QString& password, const QString& project)
{
std::map<QString, QString> whereFields {{"userName", user}, {"password", password}};
QString request = prepareMessage("Login", "Security", std::map<QString, QString>(), whereFields); // Generates the XML message for the API
sendMessage(request);
// Wait for data to arrive - How ?
std::stringstream xmlResult = getXmlData(result_); // Remove the header from the API response and convert the QByteArray to a std::stringstream
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load(xmlResult);
throwOnError(doc);
pugi::xpath_node session = doc.select_node("/EXECUTION/TASK/RESULTSET/DATASETS/DATASET/secId");
sessionId_ = QString::fromStdString(session.node().first_child().value());
projectName_ = project;
emit taskCompleted();
}
#包括“client.h”
#包括
#包括
#包括
#包括
#包括“task.h”//生成API消息,不相关
客户端::客户端(常量字符串和服务器、常量字符串和端口、QObject*父级):
QObject(父对象)
{
connectToServer(服务器、端口);
连接(&socket;&qtcsocket::readyRead,this,&Client::getResult);
}
无效客户端::connectToServer(常量QString和服务器、常量QString和端口)
{
布尔ok;
int-portNumber=port.toInt(&ok);
如果(确定){
if(socket.state()==qtcsocket::SocketState::ConnectedState)
socket_u.disconnectFromHost();
套接字连接到主机(服务器、端口号);
}否则{
抛出tr(“无法连接到端口%2上的服务器%1。请确保提供的信息正确。”)
.arg(服务器)
.arg(港口);
}
}
无效客户端::throwOnError(const pugi::xml\u文档和文档)
{
pugi::xpath_node_set errors=doc。选择_节点(“/EXECUTION/TASK/RESULTSET/RESULT/MESSAGE”);
std::字符串错误_message=“”;
for(pugi::xpath_node_set::const_iterator it=errors.begin();it!=errors.end();+it)
{
pugi::xml_node node=it->node();
如果(std::string(node.attribute(“type”).value())=“错误”||
std::string(node.attribute(“type”).value()=“警告”)
错误消息+=node.child_值();
}
如果(!error_message.empty())
抛出std::exception(error_message.c_str());
}
无效客户端::发送消息(常量QString和消息)
{
outMessage=消息;
结果清除();
socket.write(message.toUtf8());
}
void客户端::getResult()
{
发射startreding();
while(套接字字节可用()>0){
result.append(socket.readAll());
插座uu.flush();
}
resultMessage=QString(result_u2;);
发出令人恐惧的声音;
}
无效客户端::登录(const-QString和用户、const-QString和密码、const-QString和项目)
{
映射whereFields{{“userName”,user},{“password”,password};
QString request=prepareMessage(“Login”,“Security”,std::map(),whereFields);//为API生成XML消息
发送消息(请求);
//等待数据到达-如何?
std::stringstream xmlResult=getXmlData(result);//从API响应中删除头并将QByteArray转换为std::stringstream
pugi::xml_文档文档;
pugi::xml_parse_result=doc.load(xmlResult);
错误(doc);
pugi::xpath_node session=doc。选择_节点(“/EXECUTION/TASK/RESULTSET/DATASET/DATASET/secId”);
sessionId_QString::fromStdString(session.node().first_child().value());
projectName=项目;
emit taskCompleted();
}
客户:h
#ifndef Client_H
#define Client_H
#include <QObject>
#include <QTcpSocket>
#include <QByteArray>
#include <map>
#include <set>
#include "pugixml.hpp"
class Client : public QObject
{
Q_OBJECT
public:
Client(QObject* parent = 0) : QObject(parent) {}
Client(const QString& server, const QString& port, QObject* parent = 0);
// Connection
void connectToServer(const QString& server, const QString& port);
void login(const QString& user, const QString& password, const QString& project);
void logout();
QString const getSessionId() { return sessionId_; }
void throwOnError(const pugi::xml_document& doc);
QString sessionId() const { return sessionId_; }
QString outMessage; // For testing
QString resultMessage; // For testing
signals:
void ready();
void startReading();
void finishedReading();
void taskCompleted();
private slots:
void getResult();
private:
void sendMessage(const QString& message);
QTcpSocket socket_;
QString sessionId_;
QString projectName_;
QByteArray result_;
};
#endif // Client_H
\ifndef客户端
#定义客户端
#包括
#包括
#包括
#包括
#包括
#包括“pugixml.hpp”
类客户端:公共QObject
{
Q_对象
公众:
客户端(QObject*parent=0):QObject(parent){}
客户端(常量字符串和服务器,常量字符串和端口,QObject*parent=0);
//联系
无效连接到服务器(常量字符串和服务器、常量字符串和端口);
无效登录(const-QString和用户、const-QString和密码、const-QString和项目);
无效注销();
QString常量getSessionId(){return sessionId_;}
void throwOnError(const pugi::xml_文档和文档);
QString sessionId()常量{return sessionId_;}
QString outMessage;//用于测试
QString resultMessage;//用于测试
信号:
void ready();
void startreding();
无效完成恐惧();
void taskCompleted();
专用插槽:
void getResult();
私人:
无效发送消息(常量字符串和消息);
QTcpSocket插座;
QString sessionId;
QString项目名称;
QByteArray结果;
};
#endif//Client_H
所有waitForXyz
方法都应被视为断开代码的移植辅助工具。在很少的情况下使用它们是正确的,我还没有看到任何这样的问题出现。不要等待,而是将插槽连接到readyRead
信号,以便在新数据可用时异步运行代码,并将其收集到QByteArray
缓冲区中。增量解析该缓冲区,直到解析器指示最顶端的元素已关闭。我可以使用此方法获取数据,但我不确定如何等待才能处理数据-如果我不清楚,请原谅,我试图实现的是找到一种方法来知道数据何时可用以开始处理它。我已经说过如何:将插槽连接到套接字的readyRead
信号。每次数据块到达时都会通知您。您需要将这些块拼接在一起并解析它们。取决于