当前位置: 首页 > 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.xdnf.cn/news/1366507.html

相关文章:

  • 安全合规:AC(上网行为安全)--下
  • vue 一键打包上传
  • Genymotion 虚拟机如何安装 APK?(ARM 插件安装教程)
  • ICCV 2025|TRACE:无需标注,用3D高斯直接学习物理参数,从视频“预知”未来!
  • 二、添加3D形状
  • More Effective C++ 条款07:不要重载、和,操作符
  • 【系统架构设计师】数据库设计(一):数据库技术的发展、数据模型、数据库管理系统、数据库三级模式
  • 审核问题——首次进入APP展示隐私政策弹窗
  • 大模型(一)什么是 MCP?如何使用 Charry Studio 集成 MCP?
  • 深分页实战
  • 计算机网络:HTTP、抓包、TCP和UDP报文及重要概念
  • GPT5的Test-time compute(测试时计算)是什么?
  • Legion Y7000P IRX9 DriveList
  • HTTP 与 HTTPS 深度解析:从原理到实际应用
  • 链表OJ习题(1)
  • 1. 并发产生背景 并发解决原理
  • pytest 并发执行用例(基于受限的测试资源)
  • 现代C++工具链实战:CMake + Conan + vcpkg依赖管理
  • week4-[一维数组]数码个数
  • k8s笔记02概述
  • C++|UDP通讯使用总结
  • HTML应用指南:利用GET请求获取MSN 天气数据并可视化
  • [系统架构设计师]应用数学(二十一)
  • list容器的使用
  • GNN:用MPNN(消息传递神经网络)落地最短路径问题模型训练全流程
  • 用 GSAP + ScrollTrigger 打造沉浸式视频滚动动画
  • 【Day 33】Linux-Mysql日志
  • DDR3入门系列(二)------DDR3硬件电路及Xilinx MIG IP核介绍
  • linux 正则表达式学习
  • 使用 gemini 来分析 github 项目