优化相机模块,优化rpc模块
This commit is contained in:
BIN
Binary file not shown.
@@ -8,6 +8,23 @@
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <windows.h>
|
||||
#include <QDateTime>
|
||||
#include <QCoreApplication>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QCryptographicHash>
|
||||
#include <QScopedPointer>
|
||||
#include <QBuffer>
|
||||
#include <QPointer>
|
||||
#include <QRegularExpression>
|
||||
#include <QDataStream>
|
||||
#include <QElapsedTimer>
|
||||
#include <QMutexLocker>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
static QProcess* process = nullptr;
|
||||
static HANDLE jobHandle = nullptr;
|
||||
rpc_finsTcp* create()
|
||||
@@ -61,9 +78,8 @@ bool rpc_finsTcp::readData(std::vector<cv::Mat>& vec_mat, QByteArray& data)
|
||||
ptr = new JsonRpcClient("127.0.0.1", 9000);
|
||||
read_JsonRpcClient[data] = ptr;
|
||||
}
|
||||
//auto result = read_JsonRpcClient[data]->call("excuteCli", QJsonArray{ QString(data) }, "finstcp");
|
||||
//data = variantListToByteArray(result);
|
||||
data = ptr->finsReadCall("excuteCli", QString(data), "finstcp");
|
||||
QByteArray resp = ptr->finsReadCall("excuteCli", QString(data), "finstcp");
|
||||
data = resp; // 已是解码后的原始字节
|
||||
return true;
|
||||
}
|
||||
bool ifRetryCMD = false;
|
||||
@@ -136,6 +152,8 @@ bool rpc_finsTcp::writeData(std::vector<cv::Mat>& vec_mat, QByteArray& data){
|
||||
readDataQueue.append(data);
|
||||
}
|
||||
else {
|
||||
if (data.contains("null"))
|
||||
return true;
|
||||
if(data.contains("Heart") == false)
|
||||
qDebug() << data;
|
||||
emit writeCallSignal("excuteCli", QJsonArray{ QString(data) }, "finstcp");
|
||||
@@ -146,7 +164,7 @@ bool rpc_finsTcp::writeData(std::vector<cv::Mat>& vec_mat, QByteArray& data){
|
||||
|
||||
bool rpc_finsTcp::initParas(QByteArray& data){
|
||||
|
||||
startProcess("./json_rpc_server.exe");
|
||||
startProcess("./json_rpc_server_1_1_0.exe");
|
||||
subThread = new QThread(this);
|
||||
write_JsonRpcClient = new JsonRpcClientWorker();
|
||||
write_JsonRpcClient->moveToThread(subThread);
|
||||
@@ -220,161 +238,150 @@ bool JsonRpcClient::reconnect() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
QVariant jsonToVariant(const nlohmann::json& j)
|
||||
{
|
||||
if (j.is_null()) return QVariant();
|
||||
if (j.is_boolean()) return j.get<bool>();
|
||||
if (j.is_number_integer()) return j.get<qint64>();
|
||||
if (j.is_number_unsigned()) return static_cast<quint64>(j.get<std::uint64_t>());
|
||||
if (j.is_number_float()) return j.get<double>();
|
||||
if (j.is_string()) return QString::fromStdString(j.get<std::string>());
|
||||
|
||||
if (j.is_array()) {
|
||||
QVariantList list;
|
||||
for (const auto& el : j) list.append(jsonToVariant(el));
|
||||
return list;
|
||||
}
|
||||
|
||||
if (j.is_object()) {
|
||||
QVariantMap map;
|
||||
for (auto it = j.begin(); it != j.end(); ++it)
|
||||
map[QString::fromStdString(it.key())] = jsonToVariant(it.value());
|
||||
return map;
|
||||
}
|
||||
|
||||
return QVariant(); // fallback
|
||||
}
|
||||
QVariant JsonRpcClient::call(const QString& method, const QJsonArray& params, const QString& module)
|
||||
{
|
||||
QMutexLocker locker(&mutex_);
|
||||
if (socket_.state() != QAbstractSocket::ConnectedState) {
|
||||
qWarning() << "[JsonRpcClient] Socket not connected.";
|
||||
if (!reconnect()) return QVariant();
|
||||
}
|
||||
|
||||
QString reqStr = QString(R"({"jsonrpc":"2.0","method":"%1","params":%2,"id":%3)")
|
||||
.arg(method)
|
||||
.arg(QString::fromUtf8(QJsonDocument(params).toJson(QJsonDocument::Compact)))
|
||||
.arg(idCounter_++);
|
||||
if (!module.isEmpty()) {
|
||||
reqStr += QString(R"(,"module":"%1")").arg(module);
|
||||
}
|
||||
reqStr += "}";
|
||||
|
||||
if (socket_.write(reqStr.toUtf8()) == -1 || !socket_.waitForBytesWritten(1000)) {
|
||||
qWarning() << "[JsonRpcClient] Write failed.";
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (!socket_.waitForReadyRead(10000)) {
|
||||
qWarning() << "[JsonRpcClient] Read timeout.";
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QByteArray responseData = socket_.readAll();
|
||||
|
||||
// 使用 nlohmann json 替代 Qt 解析
|
||||
try {
|
||||
auto respJson = nlohmann::json::parse(responseData.constData(), responseData.constData() + responseData.size());
|
||||
|
||||
if (respJson.contains("error")) {
|
||||
qWarning() << "[JsonRpcClient] Error:" << QString::fromStdString(respJson["error"].dump());
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
return jsonToVariant(respJson["result"]);
|
||||
}
|
||||
catch (const nlohmann::json::parse_error& e) {
|
||||
qWarning() << "[JsonRpcClient] Parse error:" << e.what();
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
QByteArray JsonRpcClient::finsReadCall(const QString& method, const QString& params, const QString& module) {
|
||||
QMutexLocker locker(&mutex_);
|
||||
if (socket_.state() != QAbstractSocket::ConnectedState) {
|
||||
qWarning() << "[JsonRpcClient] Socket not connected.";
|
||||
if (!reconnect()) return QByteArray();
|
||||
}
|
||||
|
||||
QString reqStr = QString(R"({"jsonrpc":"2.0","method":"%1","params":["%2"],"id":%3)")
|
||||
.arg(method)
|
||||
.arg(params)
|
||||
.arg(idCounter_++);
|
||||
if (!module.isEmpty()) {
|
||||
reqStr += QString(R"(,"module":"%1")").arg(module);
|
||||
}
|
||||
reqStr += "}";
|
||||
|
||||
if (socket_.write(reqStr.toUtf8()) == -1 || !socket_.waitForBytesWritten(1000)) {
|
||||
qWarning() << "[JsonRpcClient] Write failed.";
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
if (!socket_.waitForReadyRead(10000)) {
|
||||
qWarning() << "[JsonRpcClient] Read timeout.";
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray responseData = socket_.readAll();
|
||||
|
||||
// 仅用QByteArray查找和分割功能解析result数组
|
||||
if (responseData.contains("error")) {
|
||||
qWarning() << "[JsonRpcClient] Error in response:" << responseData;
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
// 查找 "result": [ 和对应的 ]
|
||||
int resultPos = responseData.indexOf("\"result\"");
|
||||
if (resultPos == -1) {
|
||||
qWarning() << "[JsonRpcClient] No result field in response:" << responseData;
|
||||
return QByteArray();
|
||||
}
|
||||
int arrayStart = responseData.indexOf('[', resultPos);
|
||||
int arrayEnd = responseData.indexOf(']', arrayStart);
|
||||
if (arrayStart == -1 || arrayEnd == -1 || arrayEnd <= arrayStart) {
|
||||
qWarning() << "[JsonRpcClient] Result array not found or malformed:" << responseData;
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray arrayContent = responseData.mid(arrayStart + 1, arrayEnd - arrayStart - 1);
|
||||
// 按逗号分割
|
||||
QList<QByteArray> items = arrayContent.split(',');
|
||||
|
||||
QByteArray result;
|
||||
for (QByteArray item : items) {
|
||||
item = item.trimmed();
|
||||
bool ok = false;
|
||||
int val = item.toInt(&ok);
|
||||
if (ok) {
|
||||
result.append(static_cast<char>(val));
|
||||
} else if (!item.isEmpty()) {
|
||||
qWarning() << "[JsonRpcClient] Non-integer value in result array:" << item;
|
||||
return QByteArray();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
void JsonRpcClient::writeCall(const QString& method, const QJsonArray& params, const QString& module) {
|
||||
if (socket_.state() != QAbstractSocket::ConnectedState) {
|
||||
qWarning() << "[JsonRpcClient] Socket not connected, trying to reconnect...";
|
||||
if (!reconnect()) return;
|
||||
}
|
||||
|
||||
QJsonObject request{
|
||||
int myId = idCounter_++;
|
||||
QJsonObject req{
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", method},
|
||||
{"params", params},
|
||||
{"id", idCounter_++}
|
||||
{"id", myId}
|
||||
};
|
||||
if (!module.isEmpty()) {
|
||||
request["module"] = module;
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
|
||||
QJsonDocument doc(request);
|
||||
QByteArray data = doc.toJson(QJsonDocument::Compact);
|
||||
|
||||
if (socket_.write(data) == -1 || !socket_.waitForBytesWritten(1000)) {
|
||||
qWarning() << "[JsonRpcClient] Write failed:" << socket_.errorString();
|
||||
return;
|
||||
QJsonObject respObj;
|
||||
if (!waitAndReadResponse(myId, respObj)) {
|
||||
qWarning() << "[JsonRpcClient] Read timeout or parse error.";
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
if (respObj.contains("error")) {
|
||||
qWarning() << "[JsonRpcClient] Error:" << QJsonDocument(respObj["error"].toObject()).toJson(QJsonDocument::Compact);
|
||||
return QByteArray();
|
||||
}
|
||||
QString b64 = respObj.value("result").toString();
|
||||
QByteArray decoded = QByteArray::fromBase64(b64.toUtf8());
|
||||
return decoded;
|
||||
}
|
||||
|
||||
QList<QByteArray> JsonRpcClient::extractJsonFrames(QByteArray& buffer) {
|
||||
QList<QByteArray> 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);
|
||||
}
|
||||
@@ -14,13 +14,12 @@
|
||||
#include <QTimer>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <qjsonarray.h>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QHostAddress>
|
||||
#include <qmap.h>
|
||||
#include <qthread.h>
|
||||
#include <nlohmannJson.hpp>
|
||||
enum connectionStatus {
|
||||
None,
|
||||
Disconnected,
|
||||
@@ -36,13 +35,16 @@ public:
|
||||
QByteArray finsReadCall(const QString& method, const QString& params = "", const QString& module = QString());
|
||||
bool reconnect(); // 主动重连,或 call() 失败时调用
|
||||
private:
|
||||
|
||||
QMutex mutex_; // 确保线程安全
|
||||
// 解析累计缓冲中的完整 JSON 帧(可能存在粘包/拆包)
|
||||
QList<QByteArray> extractJsonFrames(QByteArray& buffer);
|
||||
bool waitAndReadResponse(int expectId, QJsonObject& outResp, int timeoutMs = 8000);
|
||||
QJsonObject sendRequestBuildAndAwait(const QJsonObject& req, int timeoutMs = 8000);
|
||||
QMutex mutex_; // 确保线程安全
|
||||
QTcpSocket socket_;
|
||||
QString host_;
|
||||
quint16 port_;
|
||||
int idCounter_;
|
||||
|
||||
QByteArray recvBuffer_; // 累计接收缓冲
|
||||
};
|
||||
class JsonRpcClientWorker : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Reference in New Issue
Block a user