#include "BeltTearingPresenter.h" #include #include #include #include #include #include #include #include #include #include BeltTearingPresenter::BeltTearingPresenter(QObject *parent) : QObject(parent) , m_tcpServer(new QTcpServer(this)) , m_dataTimer(new QTimer(this)) , m_port(0) { // 连接信号槽 connect(m_tcpServer, &QTcpServer::newConnection, this, &BeltTearingPresenter::onNewConnection); connect(m_dataTimer, &QTimer::timeout, this, &BeltTearingPresenter::onSendSimulatedData); } BeltTearingPresenter::~BeltTearingPresenter() { stopServer(); } bool BeltTearingPresenter::startServer(quint16 port) { if (m_tcpServer->isListening()) { stopServer(); } m_port = port; bool result = m_tcpServer->listen(QHostAddress::Any, port); if (result) { std::cout << "TCP server started on port " << port << std::endl; } else { std::cout << "Failed to start TCP server: " << m_tcpServer->errorString().toStdString() << std::endl; } return result; } void BeltTearingPresenter::stopServer() { // 断开所有客户端连接 for (auto it = m_clients.begin(); it != m_clients.end(); ++it) { it.value()->disconnectFromHost(); } m_clients.clear(); // 停止服务器监听 if (m_tcpServer->isListening()) { m_tcpServer->close(); } // 停止数据发送定时器 stopSendingSimulatedData(); m_port = 0; } void BeltTearingPresenter::startSendingSimulatedData() { // 启动定时器,每2秒发送一次模拟数据 m_dataTimer->start(1000); } void BeltTearingPresenter::stopSendingSimulatedData() { if (m_dataTimer->isActive()) { m_dataTimer->stop(); } } void BeltTearingPresenter::onNewConnection() { while (m_tcpServer->hasPendingConnections()) { QTcpSocket *socket = m_tcpServer->nextPendingConnection(); // 生成客户端ID QString clientId = generateClientId(socket); // 存储客户端连接 m_clients[clientId] = socket; // 连接客户端信号 connect(socket, &QTcpSocket::disconnected, this, &BeltTearingPresenter::onClientDisconnected); std::cout << "Client connected: " << clientId.toStdString() << std::endl; // 发送欢迎消息 QByteArray welcomeMsg = "Welcome to BeltTearing Server!"; socket->write(welcomeMsg); } } void BeltTearingPresenter::onClientDisconnected() { QTcpSocket *socket = qobject_cast(sender()); if (!socket) { return; } // 查找断开连接的客户端ID QString clientId; for (auto it = m_clients.begin(); it != m_clients.end(); ++it) { if (it.value() == socket) { clientId = it.key(); break; } } if (!clientId.isEmpty()) { m_clients.remove(clientId); std::cout << "Client disconnected: " << clientId.toStdString() << std::endl; } socket->deleteLater(); } void BeltTearingPresenter::onSendSimulatedData() { static unsigned int nCount = 0; nCount++; // 向所有连接的客户端发送模拟数据 for (auto it = m_clients.begin(); it != m_clients.end(); ++it) { QTcpSocket *socket = it.value(); if (socket->state() == QAbstractSocket::ConnectedState) { if(nCount % 2 == 0){ sendSimulatedImage(socket); }else{ sendSimulatedTearingData(socket); } // 随机选择发送图像或日志记录 // sendSimulatedImage(socket); // sendSimulatedLogRecords(socket); // sendSimulatedTearingData(socket); } } } void BeltTearingPresenter::sendSimulatedImage(QTcpSocket *socket) { // 创建一个模拟的图像 cv::Mat image(480, 640, CV_8UC3, cv::Scalar(128, 128, 128)); // 在图像上绘制一些随机内容 cv::circle(image, cv::Point(320, 240), 50, cv::Scalar(0, 0, 255), -1); cv::rectangle(image, cv::Rect(100, 100, 200, 150), cv::Scalar(0, 255, 0), 2); static unsigned int s_imageCount = 0; // 在图像上叠加数字 QString numberText = QString::number(++s_imageCount); // 生成一个随机数 cv::putText(image, numberText.toStdString(), cv::Point(50, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 255, 255), 2); // 编码图像 std::vector imgBuffer; std::vector params = {cv::IMWRITE_PNG_COMPRESSION, 3}; cv::imencode(".png", image, imgBuffer, params); QByteArray byteArray(reinterpret_cast(imgBuffer.data()), imgBuffer.size()); // 创建数据包 QByteArray package; QDataStream stream(&package, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::BigEndian); stream << quint8(static_cast(ByteDataType::Image)) << quint32(byteArray.size()); package.append(byteArray); package.append("___END___\r\n"); // 发送数据 socket->write(package); std::cout << "Sent simulated image data to client" << std::endl; } void BeltTearingPresenter::sendSimulatedLogRecords(QTcpSocket *socket) { // 创建模拟日志记录 QJsonArray logRecords; for (int i = 0; i < 3; i++) { QJsonObject record; record["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate); record["level"] = QString("INFO"); record["message"] = QString("Simulated log message %1").arg(i + 1); record["source"] = QString("BeltTearingDetector"); logRecords.append(record); } // 将日志记录转换为JSON字符串 QJsonDocument doc(logRecords); QByteArray message = doc.toJson(QJsonDocument::Compact); // 创建数据包 QByteArray package; QDataStream stream(&package, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::BigEndian); stream << quint8(static_cast(ByteDataType::Text)) << quint32(message.size()); package.append(message); package.append("___END___\r\n"); // 发送数据 socket->write(package); std::cout << "Sent simulated log records to client" << std::endl; } void BeltTearingPresenter::sendSimulatedTearingData(QTcpSocket *socket) { // 创建模拟撕裂数据 QJsonArray tearingDataArray; // 生成随机数量的撕裂数据(1-3个) int tearingCount = QRandomGenerator::global()->bounded(1, 4); for (int i = 0; i < tearingCount; i++) { QJsonObject tearingInfo; // 随机生成撕裂数据 int level = QRandomGenerator::global()->bounded(1, 4); // 1-3级 int tearStatus = QRandomGenerator::global()->bounded(1, 4); // 1-3状态 QString statusStr; switch (tearStatus) { case 1: statusStr = "新的撕裂"; break; case 2: statusStr = "进行中"; break; case 3: statusStr = "已完成"; break; default: statusStr = "无效撕裂"; break; } // 填充撕裂信息 tearingInfo.insert("level", QString::number(level)); tearingInfo.insert("id", QString::number(QRandomGenerator::global()->bounded(1000, 9999))); tearingInfo.insert("tearStatus", statusStr); tearingInfo.insert("tearType", QString::number(QRandomGenerator::global()->bounded(1, 5))); tearingInfo.insert("statLineIdx", QString::number(QRandomGenerator::global()->bounded(1, 100))); tearingInfo.insert("endLineIdx", QString::number(QRandomGenerator::global()->bounded(1, 100))); tearingInfo.insert("tearDepth", QString::number(QRandomGenerator::global()->bounded(1, 1000))); tearingInfo.insert("tearWidth", QString::number(QRandomGenerator::global()->bounded(1, 500))); tearingInfo.insert("tearLength", QString::number(QRandomGenerator::global()->bounded(1, 1000))); tearingInfo.insert("roiLeft", QString::number(QRandomGenerator::global()->bounded(1, 200))); tearingInfo.insert("roiRight", QString::number(QRandomGenerator::global()->bounded(200, 400))); tearingInfo.insert("roiTop", QString::number(QRandomGenerator::global()->bounded(1, 100))); tearingInfo.insert("roiBottom", QString::number(QRandomGenerator::global()->bounded(100, 300))); tearingInfo.insert("imageFile", QString("/Image/Tearing/image_%1__.jpg").arg(QRandomGenerator::global()->bounded(1, 100))); tearingInfo.insert("older", (QRandomGenerator::global()->bounded(0, 2) == 0) ? "-" : "旧伤"); tearingDataArray.append(tearingInfo); } // 将撕裂数据转换为JSON字符串 QJsonDocument doc(tearingDataArray); QByteArray message = doc.toJson(QJsonDocument::Compact); // 创建数据包 QByteArray package; QDataStream stream(&package, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::BigEndian); stream << quint8(static_cast(ByteDataType::Text)) << quint32(message.size()); package.append(message); package.append("___END___\r\n"); // 发送数据 socket->write(package); std::cout << "Sent simulated tearing data to client" << std::endl; } QString BeltTearingPresenter::generateClientId(QTcpSocket *socket) { // 使用UUID生成唯一的客户端ID return QUuid::createUuid().toString(); }