280 lines
9.6 KiB
C++
280 lines
9.6 KiB
C++
#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();
|
||
}
|