该TCP服务器调试助手是用于测试和监控基于TCP协议的网络通信工具,能够帮助开发者便捷地进行网络通信调试。通过简洁的界面设计,用户可以轻松配置、管理TCP端口的连接,收发消息并进行数据监控分析。以下是该工具的主要功能:
123
。1000
毫秒,即每秒发送一次。通过百度网盘分享的文件:TCP服务器调试助手.zip
链接:https://pan.baidu.com/s/1UF_fEztbQnk2UIJJUR7s3g?pwd=cedu
提取码:cedu
// tcpserver.h #ifndef TCPSERVER_H #define TCPSERVER_H #include #include #include #include #define tc(a) QString::fromLocal8Bit(a) class TcpServer : public QThread { Q_OBJECT public: explicit TcpServer(QObject *parent = nullptr); void run() override; // 线程入口点 bool startServer(int port); // 启动服务器 void closeServer(); void sendToAllClients(const QByteArray &message); // 群发消息 void sendToClient(qintptr socketDescriptor, const QByteArray &message); // 发送消息给指定客户端 signals: void clientConnected(qintptr socketDescriptor); // 新客户端连接信号 void clientDisconnected(qintptr socketDescriptor); // 客户端断开信号 void errors(int index, const QString &msg); // 错误信号 void warnings(int index, const QString &msg); // 警告信号 void informations(int index, const QString &msg); // 信息信号 void ClientInfor(const long long socketDescriptor,const QByteArray &msg,const bool isRecv) ; ///<接收客户端信息 private slots: void onNewConnection(); // 新客户端连接时触发 void onClientDisconnected(); // 客户端断开时触发 void onReadyRead(); // 客户端有数据时触发 private: QTcpServer *tcpServer; // TCP服务器 QMap clients; // 保存客户端列表 }; #endif // TCPSERVER_H
// tcpserver.cpp #include "tcpserver.h" #include #include TcpServer::TcpServer(QObject *parent) : QThread(parent), tcpServer(nullptr) { } void TcpServer::run() { exec(); // 启动线程事件循环 } // 启动服务器并监听指定端口 bool TcpServer::startServer(int port) { tcpServer = new QTcpServer(); if (!tcpServer->listen(QHostAddress::Any, static_cast(port))) { emit errors(1, tc("服务器启动失败:%1 端口: ").arg(tcpServer->errorString()) + QString::number(port)); return false; } connect(tcpServer, &QTcpServer::newConnection, this, &TcpServer::onNewConnection); emit informations(1, tc("服务器启动成功,监听端口: ") + QString::number(port)); return true; } void TcpServer::closeServer() { tcpServer->close(); } // 当有新客户端连接时 void TcpServer::onNewConnection() { QTcpSocket *clientSocket = tcpServer->nextPendingConnection(); qintptr socketDescriptor = clientSocket->socketDescriptor(); clients.insert(socketDescriptor, clientSocket); // 添加到客户端列表 connect(clientSocket, &QTcpSocket::disconnected, this, &TcpServer::onClientDisconnected); connect(clientSocket, &QTcpSocket::readyRead, this, &TcpServer::onReadyRead); emit clientConnected(socketDescriptor); // 触发客户端连接信号 emit informations(2, tc("新的客户端连接,描述符: ") + QString::number(socketDescriptor)); } // 当客户端断开连接时 void TcpServer::onClientDisconnected() { QTcpSocket *clientSocket = qobject_cast(sender()); if (clientSocket) { qintptr socketDescriptor=0; for (auto key : clients.keys()) { if(clients[key]==clientSocket) socketDescriptor = key; } clients.remove(socketDescriptor); // 从客户端列表中移除 emit clientDisconnected(socketDescriptor); // 触发客户端断开信号 emit warnings(1, tc("客户端断开连接,描述符: ") + QString::number(socketDescriptor)); clientSocket->deleteLater(); } } // 当有客户端发送数据时 void TcpServer::onReadyRead() { QTcpSocket *clientSocket = qobject_cast(sender()); if (clientSocket) { QByteArray data = clientSocket->readAll(); emit ClientInfor(clientSocket->socketDescriptor(), data,true); } } // 群发消息 void TcpServer::sendToAllClients(const QByteArray &message) { if(clients.keys().isEmpty()) { emit errors(1, tc("未存在可发送的客户端 ")); return; } for(auto key:clients.keys()) sendToClient(key,message); } // 发送消息给指定客户端 void TcpServer::sendToClient(qintptr socketDescriptor, const QByteArray &message) { QTcpSocket *clientSocket = clients.value(socketDescriptor, nullptr); if (clientSocket) { clientSocket->write(message); emit ClientInfor(clientSocket->socketDescriptor(), message,false); } else { emit errors(2, tc("无法找到指定的客户端,描述符: ") + QString::number(socketDescriptor)); } }
// mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include "tcpserver.h" // 定义宏用于中文字符转换 #define tc(a) QString::fromLocal8Bit(a) QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE enum RunTimeStatus { Error, ///< 错误信息 Warning, ///< 警告信息 Information, ///< 常规信息 }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); void initStyle(); //创建发送框 void createSendLinEdit(); private slots: void on_startServerButton_clicked(); // 点击启动服务器按钮 void on_stopserverButton_clicked(); void onClientConnected(qintptr socketDescriptor); // 客户端连接信号槽 void onClientDisconnected(qintptr socketDescriptor); // 客户端断开信号槽 void handleErrors(int index, const QString &msg); // 处理错误信号槽 void handleWarnings(int index, const QString &msg); // 处理警告信号槽 void handleInformations(int index, const QString &msg); // 处理信息信号槽 void handlerClientInfor(const long long id,const QByteArray &data,const bool isRecv); void writeRunTimeMsgs(const QString &msg, const int level); // 输出运行时消息 void on_clearRunTimeutton_clicked(); void on_clearRecvButton_clicked(); void on_closeTip_clicked(); private: Ui::MainWindow *ui; TcpServer *server; // TCP服务器 QStandardItemModel *model; // 共享数据模型 }; #endif // MAINWINDOW_H
// mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include "timesendwidget.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , server(new TcpServer()) // 初始化服务器 { ui->setupUi(this); // 连接服务器信号槽 connect(server, &TcpServer::clientConnected, this, &MainWindow::onClientConnected); connect(server, &TcpServer::clientDisconnected, this, &MainWindow::onClientDisconnected); connect(server, &TcpServer::errors, this, &MainWindow::handleErrors); connect(server, &TcpServer::warnings, this, &MainWindow::handleWarnings); connect(server, &TcpServer::informations, this, &MainWindow::handleInformations); connect(server, &TcpServer::ClientInfor, this, &MainWindow::handlerClientInfor); // 创建共享的数据模型 model = new QStandardItemModel(this); QStandardItem *item = new QStandardItem(tc("群发")); item->setData(-1,Qt::UserRole); model->appendRow(item); createSendLinEdit(); initStyle(); } MainWindow::~MainWindow() { delete ui; server->quit(); // 退出服务器线程 server->wait(); // 等待线程结束 delete server; } void MainWindow::initStyle() { //加载样式表 QString qss; QFile file(":/qss/psblack.css"); if (file.open(QFile::ReadOnly)) { #if 1 //用QTextStream读取样式文件不用区分文件编码 带bom也行 QStringList list; QTextStream in(&file); //in.setCodec("utf-8"); while (!in.atEnd()) { QString line; in >> line; list << line; } qss = list.join("\n"); #else //用readAll读取默认支持的是ANSI格式,如果不小心用creator打开编辑过了很可能打不开 qss = QLatin1String(file.readAll()); #endif QString paletteColor = qss.mid(20, 7); qApp->setPalette(QPalette(paletteColor)); qApp->setStyleSheet(qss); file.close(); } } void MainWindow::createSendLinEdit() { for(int i=0;i<10;i++) { TimeSendWidget *sendWidget=new TimeSendWidget; sendWidget->setComBoxModel(model); connect(sendWidget,&TimeSendWidget::sendLineData,[=](const qintptr socketDescriptor,const QByteArray &data ) { if(data.isEmpty()) { writeRunTimeMsgs(tc("信息为空,拒绝发送"),Warning); return ; } ((socketDescriptor<0)? server->sendToAllClients(data): server->sendToClient(socketDescriptor, data)); }); ui->verticalLayout->addWidget(sendWidget); } } // 启动服务器按钮 void MainWindow::on_startServerButton_clicked() { int port = ui->portspinBox->value(); if (port > 0) { if (server->startServer(port)) { writeRunTimeMsgs(tc("服务器成功启动,监听端口:") + QString::number(port), 2); ui->startServerButton->setEnabled(false); } else { writeRunTimeMsgs(tc("服务器启动失败!"), 0); } } else { writeRunTimeMsgs(tc("无效的端口号!"), 1); } } // 关闭服务器按钮 void MainWindow::on_stopserverButton_clicked() { server->closeServer(); ui->startServerButton->setEnabled(true); } // 处理客户端连接的槽函数 void MainWindow::onClientConnected(qintptr socketDescriptor) { writeRunTimeMsgs(tc("客户端连接,描述符: ") + QString::number(socketDescriptor), 2); QStandardItem *item = new QStandardItem(tc("客户端#%1").arg(socketDescriptor)); item->setData(socketDescriptor,Qt::UserRole); model->appendRow(item); } // 处理客户端断开的槽函数 void MainWindow::onClientDisconnected(qintptr socketDescriptor) { writeRunTimeMsgs(tc("客户端断开连接,描述符: ") + QString::number(socketDescriptor), 1); // 从客户端列表中移除 for (int i = 0; i < model->rowCount(); ++i) { QStandardItem *item = model->item(i); if (item && item->data(Qt::UserRole).toLongLong() == socketDescriptor) { model->removeRow(i); // 删除找到的行 break; // 如果只想删除第一个匹配的项,删除后直接跳出循环 } } } // 处理错误信号 void MainWindow::handleErrors(int index, const QString &msg) { Q_UNUSED(index); writeRunTimeMsgs(msg, Error); } // 处理警告信号 void MainWindow::handleWarnings(int index, const QString &msg) { Q_UNUSED(index); writeRunTimeMsgs( msg, Warning); } // 处理信息信号 void MainWindow::handleInformations(int index, const QString &msg) { Q_UNUSED(index); writeRunTimeMsgs(msg, Information); } void MainWindow::handlerClientInfor(const long long id, const QByteArray &data, const bool isRecv) { QString prefix; QString color; QString msg=tc("%1客户端#%2: %3").arg(isRecv?tc("接收←"):tc("发送→")).arg(id).arg(ui->isShowHexButton->isChecked()? data.toHex(' ').toUpper():QString::fromLocal8Bit(data)); if(isRecv) { //更新显示信息 ui->recvByte->setValue(ui->recvByte->value()+data.size()); ui->recvFram->setValue(ui->recvFram->value()+1); if(!ui->isShowRecvButton->isChecked()) return; prefix = tc("【接收】"); color = "#00ff00"; } else { ui->sendByte->setValue(ui->sendByte->value()+data.size()); ui->sendFram->setValue(ui->sendFram->value()+1); if(!ui->isShowSendButton->isChecked()) return; prefix = tc("【发送】"); color = "orange"; } // 获取当前时间 QString timestamp = ui->isShowTimeButton->isChecked()?QDateTime::currentDateTime().toString("hh:mm:ss(zzz)"):""; // 将消息插入到QTextEdit中并改变颜色 // 将消息插入到QTextEdit中并改变颜色 QString formattedMsg = QString("%2 %3: %4").arg(color, prefix, timestamp,msg); ui->receiveTextEdit->append(formattedMsg); } // 输出运行时消息 void MainWindow::writeRunTimeMsgs(const QString &msg, const int level) { QString prefix; QString color; // 获取当前时间 QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"); switch (level) { case 0: // 异常 prefix = tc("【异常】"); color = "red"; break; case 1: // 警报 prefix = tc("【警报】"); color = "orange"; break; case 2: // 提示 prefix = tc("【提示】"); color = "#00ff00"; break; } // 将消息插入到QTextEdit中并改变颜色 QString formattedMsg = QString("%2 %3: %4").arg(color, prefix, timestamp, msg); ui->outputTextEdit->append(formattedMsg); } void MainWindow::on_clearRunTimeutton_clicked() { ui->outputTextEdit->clear(); } void MainWindow::on_clearRecvButton_clicked() { ui->receiveTextEdit->clear(); } void MainWindow::on_closeTip_clicked() { ui->groupBox->setVisible(!ui->groupBox->isVisible()); }