GrabBag/BeltTearingServer/BeltTearingPresenter.cpp
2025-08-31 21:08:28 +08:00

280 lines
9.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "BeltTearingPresenter.h"
#include <QUuid>
#include <QDataStream>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QBuffer>
#include <QByteArray>
#include <QDateTime>
#include <iostream>
#include <QRandomGenerator>
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<QTcpSocket*>(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<uchar> imgBuffer;
std::vector<int> params = {cv::IMWRITE_PNG_COMPRESSION, 3};
cv::imencode(".png", image, imgBuffer, params);
QByteArray byteArray(reinterpret_cast<const char*>(imgBuffer.data()), imgBuffer.size());
// 创建数据包
QByteArray package;
QDataStream stream(&package, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::BigEndian);
stream << quint8(static_cast<quint8>(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<quint8>(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<quint8>(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();
}