当前位置: 首页 > news >正文

开源 C++ QT Widget 开发(六)通讯--TCP调试

文章的目的为了记录使用C++ 进行QT Widget 开发学习的经历。临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。

  相关链接:

开源 C++ QT Widget 开发(一)工程文件结构-CSDN博客

开源 C++ QT Widget 开发(二)基本控件应用-CSDN博客

开源 C++ QT Widget 开发(三)图表--波形显示器-CSDN博客

开源 C++ QT Widget 开发(四)文件--二进制文件查看编辑-CSDN博客

 开源 C++ QT Widget 开发(五)通讯--串口调试-CSDN博客

开源 C++ QT Widget 开发(六)通讯--TCP调试-CSDN博客


推荐链接:

开源 java android app 开发(一)开发环境的搭建-CSDN博客

开源 java android app 开发(二)工程文件结构-CSDN博客

开源 java android app 开发(三)GUI界面布局和常用组件-CSDN博客

开源 java android app 开发(四)GUI界面重要组件-CSDN博客

开源 java android app 开发(五)文件和数据库存储-CSDN博客

开源 java android app 开发(六)多媒体使用-CSDN博客

开源 java android app 开发(七)通讯之Tcp和Http-CSDN博客

开源 java android app 开发(八)通讯之Mqtt和Ble-CSDN博客

开源 java android app 开发(九)后台之线程和服务-CSDN博客

开源 java android app 开发(十)广播机制-CSDN博客

开源 java android app 开发(十一)调试、发布-CSDN博客

开源 java android app 开发(十二)封库.aar-CSDN博客

推荐链接:

开源C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客

开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客

开源 C# .net mvc 开发(三)WEB内外网访问(VS发布、IIS配置网站、花生壳外网穿刺访问)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-CSDN博客

开源 C# .net mvc 开发(四)工程结构、页面提交以及显示_c#工程结构-CSDN博客

开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客

本章主要内容:Tcp通讯调试工具,ip,端口等参数可设置。可以设为服务器端和客户端,同时数据可以发送文本或16进制。

一、源码分析  

1.1  界面设计 (UI)
主窗口布局:采用垂直布局,包含TCP配置区、接收数据区和发送数据区

控件组织:

TCP配置区:模式选择、地址选择、端口输入、连接按钮、状态显示

接收区:文本显示框、16进制显示选项、清空按钮

发送区:文本输入框、16进制发送选项、清空和发送按钮

1.2  核心功能
网络模式支持:
Server模式:作为TCP服务器监听连接,支持多客户端连接

Client模式:作为TCP客户端连接远程服务器

1.3  数据处理:
16进制与文本模式:支持16进制和文本两种数据格式的发送和显示

实时数据收发:能够实时接收和显示网络数据

二、所有源码

2.1  mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QComboBox>
#include <QTextEdit>
#include <QCheckBox>
#include <QPushButton>
#include <QLabel>
#include <QGroupBox>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QMessageBox>
#include <QScrollBar>
#include <QLineEdit>
#include <QHostInfo>
#include <QNetworkInterface>class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void onConnectButtonClicked();void onSendButtonClicked();void onClearReceiveButtonClicked();void onClearSendButtonClicked();void onNewConnection();void onClientConnected();void onClientDisconnected();void onReadyRead();void onTcpModeChanged(int index);private:void createUI();void initNetwork();void refreshLocalAddresses();void connectSignals();void disconnectSignals();void updateConnectionStatus();QString getClientInfo(QTcpSocket *client) const;// TCP模式选择QComboBox *tcpModeComboBox;QComboBox *localAddressComboBox;QLineEdit *portEdit;QPushButton *connectButton;QLabel *statusLabel;// 客户端连接信息QLabel *clientsLabel;// 接收区域控件QTextEdit *receiveEdit;QCheckBox *hexDisplayCheckBox;QPushButton *clearReceiveButton;// 发送区域控件QTextEdit *sendEdit;QCheckBox *hexSendCheckBox;QPushButton *clearSendButton;QPushButton *sendButton;// 网络对象QTcpServer *tcpServer;QList<QTcpSocket*> clientSockets;QTcpSocket *tcpClient;// 布局和容器QWidget *centralWidget;QVBoxLayout *mainLayout;
};#endif // MAINWINDOW_H

2.2  mainwindow.cpp文件

#include "mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), tcpServer(nullptr), tcpClient(nullptr)
{// 设置窗口大小和标题this->resize(1000, 800);this->setWindowTitle("QT TCP调试助手");// 创建界面createUI();// 初始化网络initNetwork();// 刷新本地地址refreshLocalAddresses();// 连接信号槽connectSignals();
}MainWindow::~MainWindow()
{// 关闭服务器if (tcpServer && tcpServer->isListening()) {tcpServer->close();}// 关闭所有客户端连接for (QTcpSocket *client : clientSockets) {if (client && client->state() == QAbstractSocket::ConnectedState) {client->disconnectFromHost();if (client->state() != QAbstractSocket::UnconnectedState) {client->waitForDisconnected(1000);}}delete client;}clientSockets.clear();// 关闭客户端连接if (tcpClient && tcpClient->state() == QAbstractSocket::ConnectedState) {tcpClient->disconnectFromHost();if (tcpClient->state() != QAbstractSocket::UnconnectedState) {tcpClient->waitForDisconnected(1000);}}delete tcpClient;delete tcpServer;
}void MainWindow::createUI()
{// 创建中央部件centralWidget = new QWidget(this);setCentralWidget(centralWidget);// 主布局mainLayout = new QVBoxLayout(centralWidget);mainLayout->setSpacing(10);mainLayout->setContentsMargins(10, 10, 10, 10);// 创建TCP配置区域QGroupBox *configGroup = new QGroupBox("TCP配置", centralWidget);QHBoxLayout *configLayout = new QHBoxLayout(configGroup);configLayout->setSpacing(5);// TCP模式选择QLabel *modeLabel = new QLabel("TCP模式:", configGroup);tcpModeComboBox = new QComboBox(configGroup);tcpModeComboBox->setMinimumWidth(100);tcpModeComboBox->addItems(QStringList() << "Server" << "Client");configLayout->addWidget(modeLabel);configLayout->addWidget(tcpModeComboBox);// 本地地址选择QLabel *addressLabel = new QLabel("本地地址:", configGroup);localAddressComboBox = new QComboBox(configGroup);localAddressComboBox->setMinimumWidth(150);configLayout->addWidget(addressLabel);configLayout->addWidget(localAddressComboBox);// 端口输入QLabel *portLabel = new QLabel("端口:", configGroup);portEdit = new QLineEdit(configGroup);portEdit->setMinimumWidth(80);portEdit->setText("8080");portEdit->setValidator(new QIntValidator(1, 65535, this));configLayout->addWidget(portLabel);configLayout->addWidget(portEdit);// 连接/监听按钮connectButton = new QPushButton("启动监听", configGroup);connectButton->setFixedWidth(100);configLayout->addWidget(connectButton);// 状态标签statusLabel = new QLabel("未连接", configGroup);configLayout->addWidget(statusLabel);// 客户端连接信息标签clientsLabel = new QLabel("客户端: 0", configGroup);configLayout->addWidget(clientsLabel);configLayout->addStretch();// 创建接收区域QGroupBox *receiveGroup = new QGroupBox("接收数据", centralWidget);QVBoxLayout *receiveLayout = new QVBoxLayout(receiveGroup);// 接收文本框receiveEdit = new QTextEdit(receiveGroup);receiveEdit->setReadOnly(true);receiveEdit->setMinimumHeight(300);receiveLayout->addWidget(receiveEdit);// 接收选项QHBoxLayout *receiveOptionsLayout = new QHBoxLayout();hexDisplayCheckBox = new QCheckBox("16进制显示", receiveGroup);clearReceiveButton = new QPushButton("清空接收", receiveGroup);clearReceiveButton->setFixedWidth(80);receiveOptionsLayout->addWidget(hexDisplayCheckBox);receiveOptionsLayout->addWidget(clearReceiveButton);receiveOptionsLayout->addStretch();receiveLayout->addLayout(receiveOptionsLayout);// 创建发送区域QGroupBox *sendGroup = new QGroupBox("发送数据", centralWidget);QVBoxLayout *sendLayout = new QVBoxLayout(sendGroup);// 发送文本框sendEdit = new QTextEdit(sendGroup);sendEdit->setMaximumHeight(150);sendLayout->addWidget(sendEdit);// 发送选项QHBoxLayout *sendOptionsLayout = new QHBoxLayout();hexSendCheckBox = new QCheckBox("16进制发送", sendGroup);clearSendButton = new QPushButton("清空发送", sendGroup);clearSendButton->setFixedWidth(80);sendButton = new QPushButton("发送", sendGroup);sendButton->setFixedWidth(80);sendOptionsLayout->addWidget(hexSendCheckBox);sendOptionsLayout->addWidget(clearSendButton);sendOptionsLayout->addWidget(sendButton);sendOptionsLayout->addStretch();sendLayout->addLayout(sendOptionsLayout);// 将各个区域添加到主布局mainLayout->addWidget(configGroup);mainLayout->addWidget(receiveGroup);mainLayout->addWidget(sendGroup);// 设置布局比例mainLayout->setStretch(0, 1);  // 配置区域mainLayout->setStretch(1, 4);  // 接收区域mainLayout->setStretch(2, 2);  // 发送区域
}void MainWindow::initNetwork()
{tcpServer = new QTcpServer(this);tcpClient = new QTcpSocket(this);
}void MainWindow::refreshLocalAddresses()
{localAddressComboBox->clear();// 添加本地地址选项localAddressComboBox->addItem("127.0.0.1");localAddressComboBox->addItem("0.0.0.0");// 获取本机所有IP地址QList<QHostAddress> addresses = QNetworkInterface::allAddresses();for (const QHostAddress &address : addresses) {if (address.protocol() == QAbstractSocket::IPv4Protocol &&address != QHostAddress::LocalHost) {localAddressComboBox->addItem(address.toString());}}localAddressComboBox->setCurrentIndex(0);
}void MainWindow::connectSignals()
{connect(connectButton, &QPushButton::clicked, this, &MainWindow::onConnectButtonClicked);connect(sendButton, &QPushButton::clicked, this, &MainWindow::onSendButtonClicked);connect(clearReceiveButton, &QPushButton::clicked, this, &MainWindow::onClearReceiveButtonClicked);connect(clearSendButton, &QPushButton::clicked, this, &MainWindow::onClearSendButtonClicked);connect(tcpModeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),this, &MainWindow::onTcpModeChanged);connect(tcpServer, &QTcpServer::newConnection, this, &MainWindow::onNewConnection);connect(tcpClient, &QTcpSocket::connected, this, &MainWindow::onClientConnected);connect(tcpClient, &QTcpSocket::disconnected, this, &MainWindow::onClientDisconnected);connect(tcpClient, &QTcpSocket::readyRead, this, &MainWindow::onReadyRead);
}void MainWindow::disconnectSignals()
{disconnect(tcpServer, &QTcpServer::newConnection, this, &MainWindow::onNewConnection);disconnect(tcpClient, &QTcpSocket::connected, this, &MainWindow::onClientConnected);disconnect(tcpClient, &QTcpSocket::disconnected, this, &MainWindow::onClientDisconnected);disconnect(tcpClient, &QTcpSocket::readyRead, this, &MainWindow::onReadyRead);for (QTcpSocket *client : clientSockets) {disconnect(client, &QTcpSocket::readyRead, this, &MainWindow::onReadyRead);disconnect(client, &QTcpSocket::disconnected, this, &MainWindow::onClientDisconnected);}
}void MainWindow::onTcpModeChanged(int index)
{if (index == 0) { // Server模式connectButton->setText("启动监听");localAddressComboBox->setEnabled(true);} else { // Client模式connectButton->setText("连接服务器");localAddressComboBox->setEnabled(true);}// 断开当前连接if (tcpServer->isListening()) {tcpServer->close();}if (tcpClient->state() == QAbstractSocket::ConnectedState) {tcpClient->disconnectFromHost();}statusLabel->setText("未连接");clientsLabel->setText("客户端: 0");
}void MainWindow::onConnectButtonClicked()
{QString portText = portEdit->text().trimmed();if (portText.isEmpty()) {QMessageBox::warning(this, "警告", "请输入端口号");return;}quint16 port = portText.toUShort();if (port == 0) {QMessageBox::warning(this, "警告", "端口号无效");return;}if (tcpModeComboBox->currentIndex() == 0) { // Server模式if (tcpServer->isListening()) {// 停止监听tcpServer->close();for (QTcpSocket *client : clientSockets) {client->disconnectFromHost();delete client;}clientSockets.clear();connectButton->setText("启动监听");statusLabel->setText("已停止监听");clientsLabel->setText("客户端: 0");} else {// 启动监听QHostAddress address(localAddressComboBox->currentText());if (tcpServer->listen(address, port)) {connectButton->setText("停止监听");statusLabel->setText(QString("监听中: %1:%2").arg(address.toString()).arg(port));receiveEdit->append(QString("[系统] 开始监听 %1:%2").arg(address.toString()).arg(port));} else {QMessageBox::critical(this, "错误", "监听失败: " + tcpServer->errorString());}}} else { // Client模式if (tcpClient->state() == QAbstractSocket::ConnectedState) {// 断开连接tcpClient->disconnectFromHost();connectButton->setText("连接服务器");statusLabel->setText("已断开连接");} else {// 连接服务器QHostAddress serverAddress(localAddressComboBox->currentText());tcpClient->connectToHost(serverAddress, port);if (tcpClient->waitForConnected(3000)) {connectButton->setText("断开连接");statusLabel->setText(QString("已连接到: %1:%2").arg(serverAddress.toString()).arg(port));receiveEdit->append(QString("[系统] 连接到服务器 %1:%2").arg(serverAddress.toString()).arg(port));} else {QMessageBox::critical(this, "错误", "连接失败: " + tcpClient->errorString());}}}
}void MainWindow::onSendButtonClicked()
{QString sendText = sendEdit->toPlainText();if (sendText.isEmpty()) {QMessageBox::warning(this, "警告", "发送内容不能为空");return;}QByteArray sendData;if (hexSendCheckBox->isChecked()) {// 16进制发送sendText = sendText.trimmed();sendText.replace(" ", "");sendText.replace("\n", "");sendText.replace("\t", "");sendText.replace("\r", "");if (sendText.isEmpty()) {QMessageBox::warning(this, "警告", "16进制数据不能为空");return;}if (sendText.length() % 2 != 0) {QMessageBox::warning(this, "警告", "16进制数据长度必须为偶数");return;}bool ok;for (int i = 0; i < sendText.length(); i += 2) {QString byteStr = sendText.mid(i, 2);uint8_t byte = byteStr.toUShort(&ok, 16);if (!ok) {QMessageBox::warning(this, "警告", "包含非法的16进制字符: " + byteStr);return;}sendData.append(byte);}} else {// 文本发送sendData = sendText.toUtf8();}// 发送数据if (tcpModeComboBox->currentIndex() == 0) { // Server模式// 向所有客户端发送数据for (QTcpSocket *client : clientSockets) {if (client->state() == QAbstractSocket::ConnectedState) {client->write(sendData);}}if (clientSockets.isEmpty()) {QMessageBox::warning(this, "警告", "没有客户端连接");}} else { // Client模式if (tcpClient->state() == QAbstractSocket::ConnectedState) {tcpClient->write(sendData);} else {QMessageBox::warning(this, "警告", "未连接到服务器");}}
}void MainWindow::onNewConnection()
{while (tcpServer->hasPendingConnections()) {QTcpSocket *client = tcpServer->nextPendingConnection();clientSockets.append(client);connect(client, &QTcpSocket::readyRead, this, &MainWindow::onReadyRead);connect(client, &QTcpSocket::disconnected, this, [this, client]() {receiveEdit->append(QString("[系统] 客户端断开: %1").arg(getClientInfo(client)));clientSockets.removeOne(client);client->deleteLater();clientsLabel->setText(QString("客户端: %1").arg(clientSockets.size()));});receiveEdit->append(QString("[系统] 新客户端连接: %1").arg(getClientInfo(client)));clientsLabel->setText(QString("客户端: %1").arg(clientSockets.size()));}
}void MainWindow::onClientConnected()
{receiveEdit->append("[系统] 已连接到服务器");
}void MainWindow::onClientDisconnected()
{receiveEdit->append("[系统] 与服务器断开连接");connectButton->setText("连接服务器");statusLabel->setText("连接已断开");
}void MainWindow::onReadyRead()
{QTcpSocket *socket = qobject_cast<QTcpSocket*>(sender());if (!socket) return;QByteArray data = socket->readAll();if (data.isEmpty()) return;QString prefix;if (tcpModeComboBox->currentIndex() == 0) { // Server模式prefix = QString("[客户端 %1] ").arg(getClientInfo(socket));} else { // Client模式prefix = "[服务器] ";}if (hexDisplayCheckBox->isChecked()) {// 16进制显示QString hexData;for (int i = 0; i < data.size(); i++) {hexData += QString("%1 ").arg((uint8_t)data[i], 2, 16, QLatin1Char('0')).toUpper();}receiveEdit->append(prefix + hexData.trimmed());} else {// 文本显示QString text = QString::fromUtf8(data);receiveEdit->append(prefix + text);}// 自动滚动到底部QScrollBar *scrollbar = receiveEdit->verticalScrollBar();scrollbar->setValue(scrollbar->maximum());
}void MainWindow::onClearReceiveButtonClicked()
{receiveEdit->clear();
}void MainWindow::onClearSendButtonClicked()
{sendEdit->clear();
}QString MainWindow::getClientInfo(QTcpSocket *client) const
{if (!client) return "未知";return QString("%1:%2").arg(client->peerAddress().toString()).arg(client->peerPort());
}void MainWindow::updateConnectionStatus()
{if (tcpModeComboBox->currentIndex() == 0) { // Server模式if (tcpServer->isListening()) {statusLabel->setText("监听中");} else {statusLabel->setText("未监听");}} else { // Client模式if (tcpClient->state() == QAbstractSocket::ConnectedState) {statusLabel->setText("已连接");} else {statusLabel->setText("未连接");}}
}

2.3  .pro工程文件

QT       += core gui network widgetsgreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \mainwindow.cppHEADERS += \mainwindow.hFORMS += \mainwindow.ui# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

三、显示效果

http://www.dtcms.com/a/349445.html

相关文章:

  • 微软恶意软件删除工具:官方免费的系统安全防护利器
  • CentOS安装Jenkins全流程指南
  • 3-1.Python 函数 - 函数基础(函数概述、函数的定义与调用、函数文档)
  • 8.25 朴素贝叶斯
  • [AI] Firebase Studio :AI+云端 IDE
  • C++深度优先搜素
  • 说明哈夫曼树查询过程的例子
  • 基于MATLAB的遥感图像变化检测
  • 嵌入式系统学习Day22(进程)
  • 【React】案例:B站评论
  • C#/.NET/.NET Core技术前沿周刊 | 第 51 期(2025年8.18-8.24)
  • Coze用户账号设置修改用户头像-后端源码
  • 【系统架构设计师】数据库设计(一):数据库技术的发展、数据模型、数据库管理系统、数据库三级模式
  • 容器学习day02
  • [React]Antd Cascader组件地区选择
  • SpringBoot整合Elasticsearch
  • SQL语法指南
  • Docker基本使用方法和常用命令
  • Spring文件上传核心技术解析
  • Java 编辑器与 IDE:开发者手中的利剑与盾牌
  • 彻底解决PyCharm中Matplotlib无法显示图形及中文乱码问题
  • Nginx + Certbot配置 HTTPS / SSL 证书
  • 无人机航拍数据集|第21期 无人机四种动物目标检测YOLO数据集2857张yolov11/yolov8/yolov5可训练
  • 数据分析编程第三步:分组统计
  • 无人机航拍数据集|第17期 无人机油棕树目标检测YOLO数据集1803张yolov11/yolov8/yolov5可训练
  • 读《精益数据分析》:A/B测试与多变量测试
  • 【41页PPT】SAP数据仓库和数据分析方案(附下载方式)
  • 【C++游记】List的使用和模拟实现
  • 【机器学习入门】1.1 绪论:从数据到智能的认知革命
  • Java基础 8.25