210 lines
6.3 KiB
C++
210 lines
6.3 KiB
C++
|
|
#include "BeltTearingPresenter.h"
|
|||
|
|
#include <QUuid>
|
|||
|
|
#include <QDataStream>
|
|||
|
|
#include <QJsonDocument>
|
|||
|
|
#include <QJsonObject>
|
|||
|
|
#include <QJsonArray>
|
|||
|
|
#include <QBuffer>
|
|||
|
|
#include <QByteArray>
|
|||
|
|
#include <QDateTime>
|
|||
|
|
#include <iostream>
|
|||
|
|
|
|||
|
|
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()
|
|||
|
|
{
|
|||
|
|
// 向所有连接的客户端发送模拟数据
|
|||
|
|
for (auto it = m_clients.begin(); it != m_clients.end(); ++it) {
|
|||
|
|
QTcpSocket *socket = it.value();
|
|||
|
|
if (socket->state() == QAbstractSocket::ConnectedState) {
|
|||
|
|
// 随机选择发送图像或日志记录
|
|||
|
|
sendSimulatedImage(socket);
|
|||
|
|
sendSimulatedLogRecords(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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QString BeltTearingPresenter::generateClientId(QTcpSocket *socket)
|
|||
|
|
{
|
|||
|
|
// 使用UUID生成唯一的客户端ID
|
|||
|
|
return QUuid::createUuid().toString();
|
|||
|
|
}
|