GrabBag/BeltTearingServer/BeltTearingPresenter.cpp

280 lines
9.6 KiB
C++
Raw Normal View History

#include "BeltTearingPresenter.h"
#include <QUuid>
#include <QDataStream>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QBuffer>
#include <QByteArray>
#include <QDateTime>
#include <iostream>
2025-08-31 21:08:28 +08:00
#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()
{
2025-08-31 21:08:28 +08:00
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) {
2025-08-31 21:08:28 +08:00
if(nCount % 2 == 0){
sendSimulatedImage(socket);
}else{
sendSimulatedTearingData(socket);
}
// 随机选择发送图像或日志记录
2025-08-31 21:08:28 +08:00
// 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;
}
2025-08-31 21:08:28 +08:00
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();
}