// ClientHandler.cpp #include "ClientHandler.h" #include "../LicenseGenerate/LicenseConfirmWindow.h" #include "ImageEnrollWindow.h" #include "PasswordEnrollWindow.h" ClientHandler::ClientHandler(QTcpSocket* socket, QJsonArray frontBoardOneClickTest, QJsonArray frontBoardTest, QJsonArray frontBoardFuncConfig, QJsonArray frontBoardDevInfoJson, QJsonArray frontBoardLicenseJson, QJsonArray backBoardDevInfoJson, QJsonArray getPicJson, QJsonArray getVideoJson, int clientId, QObject* parent) : QObject(parent), socket(socket), frontBoardOneClickTest(frontBoardOneClickTest), frontBoardTest(frontBoardTest), frontBoardFuncConfig(frontBoardFuncConfig), frontBoardDevInfoJson(frontBoardDevInfoJson), frontBoardLicenseJson(frontBoardLicenseJson), backBoardDevInfoJson(backBoardDevInfoJson), getPicJson(getPicJson), getVideoJson(getVideoJson), currentItemIndex(0), clientId(clientId), isManualSend(false), isSingleSend(false), isClickedSend(false), size(0), isFirstDataReceived(true), processDataFunction(nullptr), isDataStuck(false), dataProcessingActive(false), isRecvVideoData(false), currentFrontBoardIndex(0), currentBackBoardIndex(0) { connect(socket, &QTcpSocket::readyRead, this, &ClientHandler::onDataReceived); connect(socket, &QTcpSocket::disconnected, this, &ClientHandler::onDisconnected); qint64 bufferSize = socket->socketOption(QAbstractSocket::ReceiveBufferSizeSocketOption).toLongLong(); /*connect(socket, QOverload::of(&QTcpSocket::error), this, &ClientHandler::onSocketError);*/ } ClientHandler::~ClientHandler() { qDebug() << "ClientHandler destroyed for clientId:" << clientId; if (readTimer) { readTimer->stop(); delete readTimer; } if (threadStatusTimer) { threadStatusTimer->stop(); delete threadStatusTimer; } if (connectionCheckTimer) { connectionCheckTimer->stop(); delete connectionCheckTimer; } } //void ClientHandler::onSocketError(QAbstractSocket::SocketError socketError) { // qWarning() << "-------------------------------Socket error:" << socketError << "clientId:" << clientId; //} void ClientHandler::startReadVideoDataTimer() { emit startReadTimer(clientId); //qDebug() << "------ startClientReadTimer clientId:" << clientId; } void ClientHandler::stopReadVideoDataTimer() { emit stopReadTimer(clientId); } qint64 getFreeMemory() { QStorageInfo storage = QStorageInfo::root(); return storage.bytesAvailable(); } void ClientHandler::checkConnectionStatus() { if (socket->state() != QTcpSocket::ConnectedState) { qCritical() << "Connection lost for clientId:" << clientId << ". Socket state:" << socket->state(); emit clientDisconnected(this); } } QString ClientHandler::getCurrentItemData() const { QString data = currentItem.value("data").toString(); qDebug() << "Getting current item data:" << data; return data; // 返回当前项的 "data" 字段 } QString ClientHandler::getCurrentFuncItemData() const { QString data = currentFuncItem.value("val").toString(); qDebug() << "Getting current funcItem val:" << data; return data; // 返回当前项的 "data" 字段 } QString ClientHandler::getCurrentItemLable() const { QString lable = currentItem.value("lable").toString(); //qDebug() << "Getting current item lable:" << lable; return lable; // 返回当前项的 "data" 字段 } QString ClientHandler::getCurrentFuncItemLable() const { QString lable = currentFuncItem.value("lable").toString(); //qDebug() << "Getting current funcItem lable:" << lable; return lable; // 返回当前项的 "data" 字段 } QString ClientHandler::getClientAddress() const { return socket->peerAddress().toString() + ":" + QString::number(socket->peerPort()); } // 实现 QRunnable 的 run 函数,在线程池中执行 void ClientHandler::run() { start(); } // 重置索引 void ClientHandler::resetCurrentItemIndex() { currentItemIndex = 0; currentFuncItemIndex = 0; itemsProcessedCount = 0; emit startTimeout(0); } // 开始处理客户端 void ClientHandler::start() { resetCurrentItemIndex(); // 初始化计数器和索引 sendNextItem(); } void ClientHandler::sendJsonItem(const QJsonArray& jsonArray, int itemIndex, const QString text, const QString& itemType) { QMutexLocker locker(&mutex); isSingleSend = true; isClickedSend = true; if (itemType == "handleVideo") { if(itemIndex == 0) isRecvVideoData = 1; else isRecvVideoData = 0; startReadVideoDataTimer(); } qDebug() << "itemIndex:" << itemIndex; qDebug() << "jsonArray.size():" << jsonArray.size(); if (itemIndex >= 0 && itemIndex < jsonArray.size()) { currentItemIndex = (itemType == "test") ? itemIndex : 0; currentFuncItemIndex = (itemType == "func") ? itemIndex : 0; QJsonObject currentItem = jsonArray[itemIndex].toObject(); if (!text.isEmpty() && currentItem.contains("val")) { QJsonValue originalValue = currentItem["val"]; if (originalValue.isDouble()) { bool ok; double doubleValue = text.toDouble(&ok); if (ok) { currentItem["val"] = doubleValue; } else { qWarning() << "Text conversion to double failed, original value is kept."; } } else if (originalValue.isString()) { currentItem["val"] = text; } } QString itemData = QJsonDocument(currentItem).toJson(); emit sendData(itemData.toUtf8()); // 设置超时处理 if (currentItem.contains("timeout")) { int timeout = currentItem.value("timeout").toInt(); if (timeout > 0) { emit startTimeout(timeout); } } } } // 发送获取设备信息按键 void ClientHandler::sendGetDevInfoItem(int itemIndex) { sendJsonItem(getDevInfoJson, itemIndex, "", "devInfo"); } // 发送取图按键 void ClientHandler::sendGetPicItem(int itemIndex, int lastClickedGetVideoCamIndex) { sendJsonItem(getPicJson, itemIndex, QString::number(lastClickedGetVideoCamIndex), "getPic"); } // 发送拉视频按键 void ClientHandler::sendGetVideoItem(int itemIndex, int video_flag) { qDebug() << "sendGetVideoItem itemIndex:" << itemIndex; sendJsonItem(getVideoJson, itemIndex, "", "handleVideo"); } // 发送License处理按键 void ClientHandler::sendLicenseItem(int itemIndex) { if (itemIndex < 0 || itemIndex >= frontBoardLicenseJson.size()) { qDebug() << "Invalid itemIndex"; return; } QJsonObject item = frontBoardLicenseJson[itemIndex].toObject(); QString label = item["lable"].toString(); if (label == "write_license") { LicenseConfirmWindow dialog("你确定要发送此授权项吗?"); if (dialog.exec() == QDialog::Accepted) { sendJsonItem(frontBoardLicenseJson, itemIndex, "", "License"); } } else { sendJsonItem(frontBoardLicenseJson, itemIndex, "", "License"); } } // 发送单独一个功能配置 JSON 项目 void ClientHandler::sendFuncItem(int itemIndex, const QString text) { //qDebug() << "sendFuncItem Text:" << text; sendJsonItem(frontBoardFuncConfig, itemIndex, text, "func"); } // 发送单独一个测试配置 JSON 项目 void ClientHandler::sendItem(int itemIndex) { QString text = ""; QJsonObject currentItem = frontBoardTest[itemIndex].toObject(); if (currentItem.contains("cmd") && currentItem["cmd"].toString() == "IMG_ENROLL") { ImageEnrollWindow dialog; if (dialog.exec() == QDialog::Accepted) { text = dialog.getFilePath(); QByteArray imageData = dialog.getImageData(); if (!imageData.isEmpty()) { text = QString::fromUtf8(imageData); } } else { return; } } else if (currentItem.contains("cmd") && currentItem["cmd"].toString() == "DEL_USER") { DelUserWindow dialog; if (dialog.exec() == QDialog::Accepted) { QString userInput = dialog.getUserInput(); if (!userInput.isEmpty() && currentItem.contains("val")) { text = userInput; } } else { return; } } else if (currentItem.contains("cmd") && currentItem["cmd"].toString() == "PASSWD_ENROLL") { PasswordEnrollWindow dialog; if (dialog.exec() == QDialog::Accepted) { text = dialog.getPassword(); } else { return; } } sendJsonItem(frontBoardTest, itemIndex, text, "test"); } void ClientHandler::sendDevInfoJsonItem(const QJsonObject& jsonItem, int itemIndex) { QMutexLocker locker(&mutex); isPowerOnSend = true; qDebug() << "itemIndex:" << itemIndex; qDebug() << "jsonItem.size():" << jsonItem.size(); QString itemData = QJsonDocument(jsonItem).toJson(); emit sendData(itemData.toUtf8()); if (jsonItem.contains("timeout")) { int timeout = jsonItem.value("timeout").toInt(); if (timeout > 0) { emit startTimeout(timeout); } } else { // 如果没有 timeout 字段,则不设置超时处理,一直等待数据接收 } } void ClientHandler::sendDevInfoItem() { // 前板 if (1) { qDebug() << "frontBoardDevInfoJson.size():" << frontBoardDevInfoJson.size(); if (currentFrontBoardIndex < frontBoardDevInfoJson.size()) { sendDevInfoJsonItem(frontBoardDevInfoJson[currentFrontBoardIndex].toObject(), 1); currentFrontBoardIndex ++; } else isPowerOnSend = false; } // 后板 else { if (currentBackBoardIndex < backBoardDevInfoJson.size()) { sendDevInfoJsonItem(backBoardDevInfoJson[currentBackBoardIndex ++].toObject(), 1); } else isPowerOnSend = false; } } // 发送下一个 JSON 项目 void ClientHandler::sendNextItem() { //qDebug() << "------> start mutex :" << __FUNCTION__; QMutexLocker locker(&mutex); isClickedSend = true; qDebug() << "------> locker(&mutex) :" << itemsProcessedCount; if (currentItemIndex < frontBoardOneClickTest.size()) { currentItem = frontBoardOneClickTest[currentItemIndex].toObject(); QString itemData = QJsonDocument(currentItem).toJson(); //qDebug() << "Sending item index:" << currentItemIndex << "data:" << itemData; if (currentItem.contains("cmd") && currentItem["cmd"].toString() == "DEL_USER") { DelUserWindow dialog; if (dialog.exec() == QDialog::Accepted) { //qDebug() << "用户确认删除,关闭窗口"; QString userInput = dialog.getUserInput(); if (!userInput.isEmpty() && currentItem.contains("val")) { currentItem["val"] = userInput; itemData = QJsonDocument(currentItem).toJson(); } } } emit sendData(itemData.toUtf8()); if (currentItem.contains("timeout")) { int timeout = currentItem.value("timeout").toInt(); if (timeout > 0) { qDebug() << "------> sendNextItem :" << itemsProcessedCount; emit startTimeout(timeout); } } else { // 如果没有 timeout 字段,则不设置超时处理,一直等待数据接收 } } else if (isManualSend) { emit allItemsProcessed(getClientAddress(), itemsProcessedCount); // 处理完毕后重置标记 isManualSend = false; isClickedSend = false; // 重置索引,可以再次一键功能测试 resetCurrentItemIndex(); } //qDebug() << "------> end mutex :" << __FUNCTION__; } void ClientHandler::RNDISClient1Data(QByteArray& data) { qDebug() << " RNDISClient1Data size:" << data.size(); } void ClientHandler::RNDISClient2Data(QByteArray& data) { qDebug() << " RNDISClient2Data size:" << data.size(); } void ClientHandler::RNDISClient3Data(QByteArray& data) { qDebug() << " RNDISClient3Data size:" << data.size(); } void ClientHandler::RNDISClient4Data(QByteArray& data) { //qDebug() << " RNDISClient4Data size:" << data.size(); } bool ClientHandler::RNDISFirstData(QByteArray& data) { //int clientType = data.at(0); // 根据实际数据格式提取标识 bool ret = true; unsigned char clientType = static_cast(data[10]); qDebug() << " clientType :" << clientType; QByteArray tmpdata = data.left(11); qDebug() << " tmpdata :" << tmpdata.toHex().data(); switch (clientType) { case 0x01: processDataFunction = &ClientHandler::RNDISClient1Data; setThreadPriority(QThread::LowestPriority); socket->setReadBufferSize(20 * 1024); break; case 0x02: processDataFunction = &ClientHandler::RNDISClient2Data; socket->setReadBufferSize(100 * 1024); data = data.mid(11); (this->*processDataFunction)(data); setThreadPriority(QThread::HighPriority); break; case 0x03: processDataFunction = &ClientHandler::RNDISClient3Data; setThreadPriority(QThread::LowPriority); socket->setReadBufferSize(20 * 1024); break; case 0x04: processDataFunction = &ClientHandler::RNDISClient4Data; setThreadPriority(QThread::LowestPriority); socket->setReadBufferSize(20 * 1024); break; default: qWarning() << "Unhandled client type:" << clientType; ret = false; break; } return ret; } void ClientHandler::onTimeoutRead() { onDataReceived(); } void ClientHandler::checkThreadStatus() { if (!QThread::currentThread()->isRunning()) { qCritical() << "Thread for clientId:" << clientId << "is not running!"; } else { qDebug() << "Thread for clientId:" << clientId << "is running normally."; } } // 检查数据是否卡住 bool ClientHandler::isData_Stuck() const { return isDataStuck; } void ClientHandler::setThreadPriority(QThread::Priority priority) { QThread* thread = QThread::currentThread(); if (thread) { thread->setPriority(priority); qDebug() << "Thread priority set to" << priority << "for clientId:" << clientId; } else { qWarning() << "Failed to set thread priority. Current thread is null."; } } // 处理数据接收 void ClientHandler::onDataReceived() { // 接收其他数据 添加区分 视频与其他数据 的标志位 qDebug() << "isRecvVideoData:" << isRecvVideoData; qDebug() << "isPowerOnSend:" << isPowerOnSend; qDebug() << "isClickedSend:" << isClickedSend; qDebug() << "isSingleSend:" << isSingleSend; if (!isRecvVideoData && (isPowerOnSend || isClickedSend || (isSingleSend && (currentItemIndex < frontBoardTest.size())))) { QByteArray allData; while (socket->bytesAvailable() > 0) { qint64 bytesAvailableBefore = socket->bytesAvailable(); //qDebug() << "Bytes available before read:" << bytesAvailableBefore << "clientId:" << clientId; QByteArray buffer; buffer.resize(qMin(bytesAvailableBefore, qint64(5 * 1024))); // 每次读取最多 5KB qint64 bytesRead = socket->read(buffer.data(), buffer.size()); if (bytesRead > 0) { buffer.resize(bytesRead); allData.append(buffer); qint64 bytesAvailableAfter = socket->bytesAvailable(); } } if ((currentItem.contains("timeout")) || (currentFuncItem.contains("timeout"))) { emit startTimeout(0); } if (!allData.isEmpty()) { //emit dataReceived(getClientAddress(), allData, 0xFF, currentItemIndex, currentFuncItemIndex, "", ""); emit dataReceived(getClientAddress(), allData, 0xFF, currentItemIndex, currentFuncItemIndex, getCurrentItemLable(), ""); if (!isSingleSend && !isPowerOnSend) { currentItemIndex ++; itemsProcessedCount ++; } } // 由于启动了 onTimeoutRead 所以 isSingleSend = false 导致连续发送 //if (isSingleSend && clientId >= 4) { if (isSingleSend) { isSingleSend = false; // 重置标志 isClickedSend = false; } else if (isPowerOnSend && currentFrontBoardIndex < frontBoardDevInfoJson.size()) { sendDevInfoItem(); } /*else if (isPowerOnSend) { qDebug() << "All items processed in onDataReceived."; emit allItemsProcessed(getClientAddress(), currentFrontBoardIndex); isPowerOnSend = false; }*/ else if (isClickedSend && (currentItemIndex < frontBoardOneClickTest.size())) { //qDebug() << "-------- start sendNextItem"; sendNextItem(); } else if(isClickedSend) { //qDebug() << "All items processed in onDataReceived."; emit allItemsProcessed(getClientAddress(), itemsProcessedCount); isClickedSend = false; //resetCurrentItemIndex(); } //qDebug() << "" << __FUNCTION__ << "------> itemsProcessedCount :" << itemsProcessedCount; } // 接收视频流数据 isRecvVideoData 置 0 else if (isRecvVideoData && (!dataProcessingActive)) { dataProcessingActive = true; QTimer::singleShot(0, this, &ClientHandler::processPendingData); } else { socket->readAll(); } } void ClientHandler::processPendingData() { if (dataProcessingActive) { try { int maxIterations = 10; // 每次处理的最大次数 QByteArray allData; while (socket->bytesAvailable() > 0 && maxIterations-- > 0) { qint64 bytesAvailableBefore = socket->bytesAvailable(); //qDebug() << "Bytes available before read:" << bytesAvailableBefore << "clientId:" << clientId; RETRY: // 分块读取数据,避免一次性读取过多数据 QByteArray buffer; buffer.resize(qMin(bytesAvailableBefore, qint64(5 * 1024))); // 每次读取最多 5KB qint64 bytesRead = socket->read(buffer.data(), buffer.size()); if (bytesRead > 0) { buffer.resize(bytesRead); allData.append(buffer); qint64 bytesAvailableAfter = socket->bytesAvailable(); /*qDebug() << "--1--Received data size:" << buffer.size() << "clientId:" << clientId << "at" << QDateTime::currentDateTime().toString(Qt::ISODate) << "bytesAvailable after read:" << bytesAvailableAfter; */ if (isFirstDataReceived) { RNDISFirstData(buffer); isFirstDataReceived = false; } if (bytesAvailableAfter > 9 * 1024) { goto RETRY; } // 检查是否bytesAvailable没有变化,避免无限循环 if (bytesAvailableBefore == bytesAvailableAfter) { qCritical() << "Bytes available did not change after read, possible infinite loop for clientId:" << clientId; break; } } else { qCritical() << "Failed to read data for clientId:" << clientId << ", bytesRead:" << bytesRead << ", socket error:" << socket->errorString(); break; } // 检查socket状态 if (socket->state() != QTcpSocket::ConnectedState) { qCritical() << "Socket disconnected for clientId:" << clientId; break; } } if (!allData.isEmpty()) { emit dataReceived(getClientAddress(), allData, 0xFF, currentItemIndex, currentFuncItemIndex, "", ""); } // 如果还有数据需要处理,继续调度处理任务 if (socket->bytesAvailable() > 0) { QTimer::singleShot(0, this, &ClientHandler::processPendingData); } else { dataProcessingActive = false; } //qDebug() << "Exiting processPendingData for clientId:" << clientId; } catch (const std::exception& e) { qCritical() << "Exception caught in processPendingData for clientId:" << clientId << " - " << e.what(); dataProcessingActive = false; } catch (...) { qCritical() << "Unknown exception caught in processPendingData for clientId:" << clientId; dataProcessingActive = false; } } } // 处理客户端断开连接 void ClientHandler::onDisconnected() { qDebug() << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"; qDebug() << "> A device is disconnected. ID:" << clientId; qDebug() << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"; emit clientDisconnected(this); socket->deleteLater(); } // 处理超时 void ClientHandler::onTimeout() { //qDebug() << "------> start mutex :" << __FUNCTION__; { QMutexLocker locker(&mutex); // 获取当前项的 "data" 字段 //QString itemData = currentItem.value("data").toString(); //emit statusUpdated(socket->peerAddress().toString(), currentItemIndex, false, itemData); emit statusUpdated(getClientAddress(), currentItemIndex + 1, currentFuncItemIndex + 1, false, getCurrentItemLable(), getCurrentFuncItemLable()); if (!isSingleSend && !isPowerOnSend) { currentItemIndex ++; itemsProcessedCount ++; } } if (isSingleSend) { isSingleSend = false; } else if (isPowerOnSend && currentFrontBoardIndex < frontBoardDevInfoJson.size()) { sendDevInfoItem(); } else if (isClickedSend && (currentItemIndex < frontBoardOneClickTest.size())) { //qDebug() << "------> onTimeout"; sendNextItem(); } else if(isClickedSend) { qDebug() << "All items processed in onTimeout."; emit allItemsProcessed(getClientAddress(), itemsProcessedCount); //resetCurrentItemIndex(); } else if (isPowerOnSend) { qDebug() << "All items processed in onTimeout."; emit allItemsProcessed(getClientAddress(), currentFrontBoardIndex); //resetCurrentItemIndex(); } //qDebug() << "------> end mutex :" << __FUNCTION__; qDebug() << "" << __FUNCTION__ << "------> itemsProcessedCount :" << itemsProcessedCount; }