#include "rpc_finsTcp.h" #include "qprocess.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static QProcess* process = nullptr; static HANDLE jobHandle = nullptr; rpc_finsTcp* create(){ qDebug() << "rpc_finsTcp create success!"; return new rpc_finsTcp; } void destory(rpc_finsTcp* ptr){ if (ptr) { delete ptr; ptr = nullptr; } qDebug() << " rpc_finsTcp destory success!"; } bool ifRun = true; rpc_finsTcp::rpc_finsTcp(){ ifRun = true; } bool m_IsFinsTcp = false; rpc_finsTcp::~rpc_finsTcp() { for (auto& client : write_JsonRpcClients) { if (client.first) { // 断开所有信号槽连接 client.first->disconnect(); if (client.first->isRunning()) { client.first->quit(); if (!client.first->wait(1000)) { qWarning() << "subThread quit timeout!"; } } // 如果 subThread 没有 parent,则需要手动 delete //if (!subThread->parent()) { // delete subThread; //} //subThread = nullptr; } if (client.second) { delete client.second; client.second = nullptr; } } if (hearBeatThread) { // 断开所有信号槽连接 hearBeatThread->disconnect(); if (hearBeatThread->isRunning()) { hearBeatThread->quit(); if (!hearBeatThread->wait(1000)) { qWarning() << "subThread quit timeout!"; } } // 如果 subThread 没有 parent,则需要手动 delete //if (!subThread->parent()) { // delete subThread; //} //subThread = nullptr; } if (hearBeatClinet) { delete hearBeatClinet; hearBeatClinet = nullptr; } qDebug() << " ~rpc_finsTcp success!"; } QQueue readDataQueue; // 从类中读数据到实例对象 QByteArray variantListToByteArray(const QVariant& var) { QByteArray byteArray; if (var.canConvert()) { QVariantList list = var.toList(); byteArray.reserve(list.size()); for (const QVariant& item : list) { // 每个元素转为 uchar 存入 QByteArray byteArray.append(static_cast(item.toInt())); } } return byteArray; } bool rpc_finsTcp::readData(std::vector& vec_mat, QByteArray& data){ JsonRpcClient* ptr = read_JsonRpcClient[data]; if(ptr == nullptr) { ptr = new JsonRpcClient("127.0.0.1", 9000); ptr->writeCall("init", QJsonArray{ m_IP,m_port }, "finstcp"); read_JsonRpcClient[data] = ptr; } QByteArray resp = ptr->finsReadCall("excuteCli", QString(data), "finstcp"); data = resp; // 已是解码后的原始字节 return true; } bool ifRetryCMD = false; // 实例对象把数据写入到类 void startProcess(const QString& exePath) { if (process) return; // 避免重复启动 process = new QProcess(); process->setProgram(exePath); process->start(); if (!process->waitForStarted(1000)) { qDebug() << "Process failed to start."; delete process; process = nullptr; return; } DWORD pid = process->processId(); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); jobHandle = CreateJobObject(nullptr, nullptr); if (jobHandle == nullptr) { qDebug() << "Failed to create job object"; return; } JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {}; jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; SetInformationJobObject(jobHandle, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)); if (!AssignProcessToJobObject(jobHandle, hProcess)) { qDebug() << "Failed to assign process to job object"; } CloseHandle(hProcess); } void stopProcess() { if (process) { if (process->state() == QProcess::Running) { process->kill(); process->waitForFinished(500); } delete process; process = nullptr; } if (jobHandle) { CloseHandle(jobHandle); jobHandle = nullptr; } } bool rpc_finsTcp::writeData(std::vector& vec_mat, QByteArray& data){ QList m_list = data.split('_'); if (m_list.size() < 4) { qCritical() << data + " m_list.size() != 4;command err"; return false; } QString commond = m_list.at(0); if (commond == "init") { m_IP = m_list.at(1); m_port = m_list.at(2).toInt(); threadCount = m_list.at(3).toInt(); } else if(data.contains("read")) { readDataQueue.append(data); } else { if (data.contains("null")) return true; if (data.contains("Heart") == true) {//专门的发送心跳线程去发送此数据 emit writeCallSignal("excuteCli", QJsonArray{ QString(data) }, "finstcp", -1); return true; } //检查是不是复数命令 QList commands = data.split('#'); int threadIndex = -1; { QMutexLocker locker(&threadUseIndexMutex); threadIndex = threadUseIndex; if (++threadUseIndex >= write_JsonRpcClients.size()) threadUseIndex = 0; } for (auto& command : commands) {//分割命令 QList commandSplit = command.split('_'); if (commandSplit.size() >= 5) {//如果是指定发送线程的 QString sendData = command.left(command.lastIndexOf("_")); emit writeCallSignal("excuteCli", QJsonArray{ QString(sendData) }, "finstcp", m_list.at(4).toInt()); } else { emit writeCallSignal("excuteCli", QJsonArray{ QString(command) }, "finstcp", threadIndex); } } // } return true; } void rpc_finsTcp::initClientAndThread(std::pair& pairData,const int& i) { pairData.first = new QThread(); pairData.second = new JsonRpcClientWorker(i); pairData.second->moveToThread(pairData.first); QObject::connect(this, &rpc_finsTcp::initRpcClient, pairData.second, &JsonRpcClientWorker::initClient, Qt::QueuedConnection); QObject::connect(this, &rpc_finsTcp::writeCallSignal, pairData.second, &JsonRpcClientWorker::writeCallSlot, Qt::QueuedConnection); pairData.first->start(); while (pairData.second->connection == None) QThread::msleep(1); if (pairData.second->connection == Disconnected) { qDebug() << "JsonRpcClientSubThread connection failed! threadId" << i; } else if (pairData.second->connection == Connected) { qDebug() << "JsonRpcClientSubThread connected successfully! threadId" << i; } } void rpc_finsTcp::initHearBeatThread() { hearBeatThread = new QThread(); hearBeatClinet = new JsonRpcClientWorker(-1); hearBeatClinet->moveToThread(hearBeatThread); QObject::connect(this, &rpc_finsTcp::initRpcClient, hearBeatClinet, &JsonRpcClientWorker::initClient, Qt::QueuedConnection); QObject::connect(this, &rpc_finsTcp::writeCallSignal, hearBeatClinet, &JsonRpcClientWorker::writeCallSlot, Qt::QueuedConnection); hearBeatThread->start(); while (hearBeatClinet->connection == None) QThread::msleep(1); if (hearBeatClinet->connection == Disconnected) { qDebug() << "JsonRpcClientSubThread connection failed! heartBeatThread"; } else if (hearBeatClinet->connection == Connected) { qDebug() << "JsonRpcClientSubThread connected successfully! threadId heartBeatThread"; } } bool rpc_finsTcp::initParas(QByteArray& data){ startProcess("./json_rpc_server_1_1_1.exe"); QThread::msleep(500); write_JsonRpcClients = std::vector>(threadCount); for (int i = 0; i < write_JsonRpcClients.size(); i++) { initClientAndThread(write_JsonRpcClients[i],i); } //心跳线程 initHearBeatThread(); //qDebug() << "返回结果:" << result; emit initRpcClient(); emit writeCallSignal("init", QJsonArray{ m_IP,m_port }, "finstcp", -1); for (int i = 0; i < write_JsonRpcClients.size(); i++) emit writeCallSignal("init", QJsonArray{ m_IP,m_port }, "finstcp", i); //QList> batchList; //batchList << qMakePair(QString("read_short"), params) // << qMakePair(QString("read_bit"), QJsonObject{ {"bit", "M0"} }); //QJsonArray resultArray = _JsonRpcClient->batchCall(batchList); //qDebug() << "批量结果:" << resultArray; return true; } bool rpc_finsTcp::run(){ // 没有用到 //qDebug() << "[info] " << __FUNCTION__ << " line:" << __LINE__ << " success!"; return true; } JsonRpcClient::JsonRpcClient(const QString& host, quint16 port) :host_(host), port_(port), idCounter_(1) { socket_.connectToHost(host_, port_); if (!socket_.waitForConnected(3000)) { qWarning() << "[JsonRpcClient] Initial connection failed:" << socket_.errorString(); _connectionStatus = Disconnected; } else { qDebug() << "[JsonRpcClient] Connected to" << host_ << ":" << port_; _connectionStatus = Connected; } } bool JsonRpcClient::reconnect() { if (socket_.state() == QAbstractSocket::ConnectedState) { return true; } socket_.abort(); // 清理旧连接 socket_.connectToHost(host_, port_); if (socket_.waitForConnected(3000)) { qDebug() << "[JsonRpcClient] Reconnected successfully."; return true; } else { qWarning() << "[JsonRpcClient] Reconnection failed:" << socket_.errorString(); return false; } } QVariant JsonRpcClient::call(const QString& method, const QJsonArray& params, const QString& module){ QMutexLocker locker(&mutex_); if (socket_.state() != QAbstractSocket::ConnectedState) { if (!reconnect()) return QVariant(); } int myId = idCounter_++; QJsonObject req{ {"jsonrpc", "2.0"}, {"method", method}, {"params", params}, {"id", myId} }; if (!module.isEmpty()) req.insert("module", module); QJsonObject resp = sendRequestBuildAndAwait(req); if (resp.contains("error")) { qWarning() << "[JsonRpcClient] Error:" << QJsonDocument(resp["error"].toObject()).toJson(QJsonDocument::Compact); return QVariant(); } if (!resp.contains("result")) return QVariant(); QJsonValue r = resp.value("result"); if (r.isString()) return r.toString(); if (r.isDouble()) return r.toDouble(); if (r.isBool()) return r.toBool(); if (r.isArray()) return r.toArray().toVariantList(); if (r.isObject()) return r.toObject().toVariantMap(); return QVariant(); } QByteArray JsonRpcClient::finsReadCall(const QString& method, const QString& params, const QString& module) { auto commands = params.split("_"); QMutexLocker locker(&mutex_); if (socket_.state() != QAbstractSocket::ConnectedState) { if (!reconnect()) return QByteArray(); } int myId = idCounter_++; QJsonArray p; p.append(params); QJsonObject req{{"jsonrpc","2.0"},{"method",method},{"params",p},{"id",myId}}; if (!module.isEmpty()) req.insert("module", module); QJsonDocument doc(req); QByteArray payload = doc.toJson(QJsonDocument::Compact); if (socket_.write(payload) == -1 || !socket_.waitForBytesWritten(1000)) { qWarning() << "[JsonRpcClient] Write failed."; return QByteArray(); } QJsonObject respObj; if (!waitAndReadResponse(myId, respObj)) { qWarning() << "[JsonRpcClient] Read timeout or parse error."; return QByteArray(); } QString b64 = respObj.value("result").toString(); QByteArray decoded = QByteArray::fromBase64(b64.toUtf8()); if (b64.contains("error") || decoded.size()% commands[3].toInt() != 0) { qWarning() << "[ERROR]" << b64; QThread::msleep(500); return b64.toUtf8(); } return decoded; } QList JsonRpcClient::extractJsonFrames(QByteArray& buffer) { QList frames; int start = -1; int braceDepth = 0; bool inString = false; char prev = 0; for (int i = 0; i < buffer.size(); ++i) { char c = buffer[i]; if (c == '"' && prev != '\\') inString = !inString; if (!inString) { if (c == '{') { if (braceDepth == 0) start = i; braceDepth++; } else if (c == '}') { braceDepth--; if (braceDepth == 0 && start != -1) { int len = i - start + 1; frames.append(buffer.mid(start, len)); start = -1; } } } prev = c; } if (braceDepth == 0) { if (!frames.isEmpty()) { int lastEnd = buffer.lastIndexOf('}'); if (lastEnd != -1) buffer = buffer.mid(lastEnd + 1); } } else { if (start > 0) buffer = buffer.mid(start); } return frames; } bool JsonRpcClient::waitAndReadResponse(int expectId, QJsonObject& outResp, int timeoutMs) { QElapsedTimer timer; timer.start(); while (timer.elapsed() < timeoutMs) { if (socket_.bytesAvailable() == 0) { int remain = timeoutMs - (int)timer.elapsed(); if (!socket_.waitForReadyRead(qMin(remain, 1000))) { continue; } } QByteArray chunk = socket_.readAll(); if (!chunk.isEmpty()) recvBuffer_.append(chunk); auto frames = extractJsonFrames(recvBuffer_); for (const QByteArray& f : frames) { QJsonParseError perr; QJsonDocument jd = QJsonDocument::fromJson(f, &perr); if (perr.error != QJsonParseError::NoError) { qWarning() << "[JsonRpcClient] parse frame error:" << perr.errorString(); continue; } if (jd.isArray()) { for (const QJsonValue& v : jd.array()) { if (!v.isObject()) continue; QJsonObject obj = v.toObject(); if (obj.value("id").toInt() == expectId) { outResp = obj; return true; } } } else if (jd.isObject()) { QJsonObject obj = jd.object(); if (obj.value("id").toInt() == expectId) { outResp = obj; return true; } } } } return false; } QJsonObject JsonRpcClient::sendRequestBuildAndAwait(const QJsonObject& req, int timeoutMs) { QByteArray payload = QJsonDocument(req).toJson(QJsonDocument::Compact); int id = req.value("id").toInt(); if (socket_.write(payload) == -1 || !socket_.waitForBytesWritten(1000)) { return QJsonObject{{"error", QJsonObject{{"code", -1},{"message", "write failed"}}}}; } QJsonObject resp; if (!waitAndReadResponse(id, resp, timeoutMs)) { return QJsonObject{{"error", QJsonObject{{"code", -2},{"message", "timeout"}}}}; } return resp; } void JsonRpcClient::writeCall(const QString& method, const QJsonArray& params, const QString& module) { call(method, params, module); }