200行C++代码写一个网络调试助手(TCP服务端TCP客户端)

news2024/11/30 4:53:31

前言

今天分享一个200行C++代码写成的QT网络调试助手。

可以先看看效果 。

因为我不喜欢用QT Designer,因此我用的组件都是使用代码布局的,所以需要设计一下布局。

界面是参考的之前写的串口助手,就是把里面的逻辑改了改,因此外观上看起来差不多。

我用的VS2019,一样用VS的小伙伴需要自行去下载QT的插件才可以编写QT的代码。

并且我们写网络相关的代码需要设置一下模块。

需要把Network模块给勾选上。

使用QtCreator的小伙伴需要在配置文件的对应位置加上下面的一段配置。

这样我们的初始配置就算完成了。

TCP服务端核心

组件布局什么的就不说了,我们直接进入核心。

使用TCP服务端我们需要使用到两个类。

我们需要把对应的头文件给加上去。

因为我这个网络助手是服务端和客户端一体的,所以当开始网络调试的时候我们需要判断当前的模式是服务端还是客户端。

当我们判断为是服务端的时候,就需要让QTcpServer的对象去监听,我们需要获取在选型中设置的本地IP和本地端口,也就是我们监听的IP和端口。

接着我们绑定一个信号“newConnection”,也就是当有客户端来连接的时候。

在这个槽函数中我们再绑定一个信号“readyRead”,也就是当客户端发来信息的时候。我们用QTcpSocket的对象去调用readAll函数去获取所有接受到的数据,然后添加到我们的接收区里。

SocketServer->listen(QHostAddress(LocalIP->text()), LocalPort->text().toUInt());//设置服务端的IP和端口
connect(SocketServer, &QTcpServer::newConnection, [&]() {                       //槽函数(被连接之后)
    SocketSocket = SocketServer->nextPendingConnection();                       //获取Socket用于通信
    connect(SocketSocket, &QTcpSocket::readyRead, [&]() {                       //槽函数(收到数据之后)
        QString buffer = SocketSocket->readAll();                               //读取接收到的数据
        ReceiveArea->appendPlainText(buffer);                                   //放入接收区
    });
});

发送数据

从服务端发送数据到客户端以及从客户端发送数据到服务端的代码都是一样的。

SocketSocket->write(SendArea->toPlainText().toLocal8Bit().data());

就是用QTcpSocket对象去调用write,里面的参数也就是发送的数据需要是char*类型的,因此我们需要把发送区里的数据转换一下格式。

TCP客户端核心

其实客户端和服务端里实现的功能差不多。

首先是先去主动去连接服务端,需要获取设置中的服务器IP和端口。

连接之后需要绑定信号“connect”,也就是连接上了服务器。

在槽函数中再绑定信号“readyRead”,跟上面服务端一样,把获取的数据放到接收区。

SocketSocket->connectToHost(ServerIP->text(),ServerPort->text().toUInt());      //设置连接的服务器IP和端口
connect(SocketSocket, &QTcpSocket::connected, [&]() {                           //槽函数(连接上之后)
        connect(SocketSocket, &QTcpSocket::readyRead, [&]() {                       //槽函数(收到数据之后)
            QString buffer = SocketSocket->readAll();                               //读取接收到的数据
            ReceiveArea->appendPlainText(buffer);                                   //放入接收区
        });
});

.cpp代码&.h代码

 其实写一个网络助手比写一个串口助手简单多了。cpp加上h文件一共才200行代码,如果使用QtDesigner去布局的话代码会更少,我代码中大部分都用来布局组件了。

除了上面的核心代码之外。还有一些小细节就是选择不同模式去使用网络调试助手(服务端或客户端)的时候,我们需要的设置是不同的,使用客户端的时候需要的是服务器的IP和端口。而使用服务端的时候需要的是本地的IP和端口。我们可以在不同模式下禁用不需要的配置。

并且当我们还没有连接服务器或是开启服务器的时候,我们是无法发送数据的,因此我们需要禁用发送数据的按钮。诸如此类的小细节还是需要我们一边写一边调试然后一边体会和修改的。

具体可以参考下面的代码,基本上把这俩cpp和h文件复制进工程文件就能使用了。

#include "SocketTool.h"

SocketTool::SocketTool(QWidget *parent): QMainWindow(parent){
    this->setFixedSize(1200,750);
    this->setWindowTitle(QString::fromLocal8Bit("网络调试助手"));

    SocketServer = new QTcpServer(this);            //服务端需要用的
    SocketSocket = new QTcpSocket(this);            //服务端和客户端都需要用的

    InitAssembly();
}

SocketTool::~SocketTool(){

}

void SocketTool::InitAssembly(void){
    ReceiveArea = new QPlainTextEdit(this);     //接收区
    SendArea = new QPlainTextEdit(this);        //发送区

    ReceiveArea->setFixedSize(800,400);
    ReceiveArea->move(30,20);
    ReceiveArea->setReadOnly(true);             //接收区设置为只读

    SendArea->setFixedSize(800,100);
    SendArea->move(30, 500);

    //初始化按钮
    ClearReceiveArea = new QPushButton(QString::fromLocal8Bit("清空接收区"), this);
    ClearSendArea = new QPushButton(QString::fromLocal8Bit("清空发送区"), this);
    SendData = new QPushButton(QString::fromLocal8Bit("发送数据"), this);
    Connect = new QPushButton(QString::fromLocal8Bit("连接"), this);
    DisConnect = new QPushButton(QString::fromLocal8Bit("断开连接"), this);

    ClearReceiveArea->setFixedSize(150, 50);
    ClearSendArea->setFixedSize(150, 50);
    SendData->setFixedSize(150, 50);
    Connect->setFixedSize(150, 50);
    DisConnect->setFixedSize(150, 50);

    ClearReceiveArea->move(680, 430);
    ClearSendArea->move(500,630);
    SendData->move(680, 630);
    Connect->move(850,630);
    DisConnect->move(1030,630);

    Mode = new QComboBox(this);
    Mode->setFixedSize(200,50);
    Mode->move(850,20);
    Mode->addItem(QString::fromLocal8Bit("TCP客户端"));
    Mode->addItem(QString::fromLocal8Bit("TCP服务端"));

    LocalIP = new QLineEdit(this);
    LocalPort = new QLineEdit(this);
    ServerIP = new QLineEdit(this);
    ServerPort = new QLineEdit(this);

    //给选型设置上默认项
    LocalIP->setText("0.0.0.0");
    LocalPort->setText("8888");
    ServerIP->setText("192.168.1.1");
    ServerPort->setText("8888");

    QVector<QLineEdit*>Edits;
    Edits.push_back(LocalIP);
    Edits.push_back(LocalPort);
    Edits.push_back(ServerIP);
    Edits.push_back(ServerPort);

    for (int i = 0; i < Edits.size(); ++i) {
        Edits[i]->setFixedSize(200, 50);
        Edits[i]->move(850, 100 + 80 * i);
    }

    QVector<QLabel*>Labels;
    QLabel* ModeLabel = new QLabel(QString::fromLocal8Bit("协议模式"), this);
    QLabel* LocalIPLabel = new QLabel(QString::fromLocal8Bit("本地IP"), this);
    QLabel* LocalPortLabel = new QLabel(QString::fromLocal8Bit("本地端口"), this);
    QLabel* ServerIPLabel = new QLabel(QString::fromLocal8Bit("服务器IP"), this);
    QLabel* ServerPortLabel = new QLabel(QString::fromLocal8Bit("服务器端口"), this);

    Labels.push_back(ModeLabel);
    Labels.push_back(LocalIPLabel);
    Labels.push_back(LocalPortLabel);
    Labels.push_back(ServerIPLabel);
    Labels.push_back(ServerPortLabel);

    for (int i = 0; i < Labels.size(); ++i) {
        Labels[i]->setFixedSize(150,50);
        Labels[i]->move(1080, 20 + 80 * i);
    }
    
    connect(ClearReceiveArea, &QPushButton::clicked, [&]() {        //清空接收区
        ReceiveArea->clear();
        });

    connect(ClearSendArea, &QPushButton::clicked, [&]() {           //清空发送区
        SendArea->clear();
        });

    connect(Mode, &QComboBox::currentTextChanged, [&]() {           //切换协议模式
        if (Mode->currentIndex() == 0) {                            //切换到客户端模式
            LocalIP->setDisabled(true);                             //不允许设置服务端的选项
            LocalPort->setDisabled(true);                           //其实也不需要禁用,但是可以更直观的看出不同模式需要哪些配置
            ServerIP->setDisabled(false);
            ServerPort->setDisabled(false);
        }else {                                                     //切换到服务端模式
            LocalIP->setDisabled(false);
            LocalPort->setDisabled(false);
            ServerIP->setDisabled(true);
            ServerPort->setDisabled(true);
        }
    });

    connect(Connect, &QPushButton::clicked, [&]() {                 //连接
        SocketConnect();
        Connect->setDisabled(true);                                 //禁用连接按钮
        DisConnect->setDisabled(false);                             //允许断开连接
        SendData->setDisabled(false);                               //允许发送数据
        });

    connect(DisConnect, &QPushButton::clicked, [&]() {              //断开连接
        SocketServer->close();              
        SocketSocket->close();  
        DisConnect->setDisabled(true);                              
        Connect->setDisabled(false);
        SendData->setDisabled(true);
        });

    connect(SendData, &QPushButton::clicked, [&]() {                //发送数据
        SocketSocket->write(SendArea->toPlainText().toLocal8Bit().data());
        });

    //一开始默认禁用下面的按钮,因为模式选型默认是客户端
    LocalIP->setDisabled(true);
    LocalPort->setDisabled(true);
    SendData->setDisabled(true);
    DisConnect->setDisabled(true);
}

//连接(核心代码)
void SocketTool::SocketConnect(void){
    if (Mode->currentIndex() == 0) {        //TCP客户端模式
        SocketSocket->connectToHost(ServerIP->text(),ServerPort->text().toUInt());      //设置连接的服务器IP和端口
        connect(SocketSocket, &QTcpSocket::connected, [&]() {                           //槽函数(连接上之后)
            connect(SocketSocket, &QTcpSocket::readyRead, [&]() {                       //槽函数(收到数据之后)
                QString buffer = SocketSocket->readAll();                               //读取接收到的数据
                ReceiveArea->appendPlainText(buffer);                                   //放入接收区
                });
            });
    }else {                                 //TCP服务端模式
        SocketServer->listen(QHostAddress(LocalIP->text()), LocalPort->text().toUInt());//设置服务端的IP和端口
        connect(SocketServer, &QTcpServer::newConnection, [&]() {                       //槽函数(被连接之后)
            SocketSocket = SocketServer->nextPendingConnection();                       //获取Socket用于通信
            connect(SocketSocket, &QTcpSocket::readyRead, [&]() {                       //槽函数(收到数据之后)
                QString buffer = SocketSocket->readAll();                               //读取接收到的数据
                ReceiveArea->appendPlainText(buffer);                                   //放入接收区
                });
            });
    }
}

#pragma once

#include <QtWidgets/QMainWindow>
#include <QPlainTextEdit>
#include <QPushButton> 
#include <QComboBox>
#include <QLineEdit>
#include <QVector> 
#include <QLabel>
#include <QTcpServer>
#include <QTcpSocket>

#include <QDebug>

class SocketTool : public QMainWindow{
    Q_OBJECT

public:
    SocketTool(QWidget *parent = nullptr);
    ~SocketTool();

private:
    QTcpServer* SocketServer;
    QTcpSocket* SocketSocket;

    QPlainTextEdit* ReceiveArea;
    QPlainTextEdit* SendArea;
    QComboBox* Mode;
    QLineEdit* LocalIP;
    QLineEdit* LocalPort;
    QLineEdit* ServerIP;
    QLineEdit* ServerPort;
    QPushButton* ClearReceiveArea;
    QPushButton* ClearSendArea;
    QPushButton* SendData;
    QPushButton* Connect;
    QPushButton* DisConnect;


    void InitAssembly(void);
    void SocketConnect(void);

};

工程文件获取(其实没必要,因为主要的代码都在上面了)

可以关注我的公众号“折途想要敲代码”,回复关键词“qt网络助手”即可获取VS的工程文件以及一个别人写好的网络调试助手。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1432128.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于网络面试题汇总

什么是TCP/IP五层模型&#xff1f;它们的作用是啥&#xff1f;基于TCP/IP实现的应用&#xff08;层协议&#xff09;有哪些&#xff1f; TCP/IP五层模型&#xff0c;从上向下分别是&#xff1a; 应用层&#xff1a;应用程序本身&#xff0c;应用层的作用是负责应用程序之间的…

比特币ETF广告战大爆发!

作者&#xff1a;秦晋 贝莱德主动发起广告攻势。 2月1日&#xff0c;据外媒Cryptoslate报道&#xff0c;贝莱德在提交给美国SEC的一份文件中显示&#xff0c;其提出一项在建筑物侧面投影比特币ETF广告计划。 据介绍&#xff0c;广告内容为&#xff1a;「IBIT」信号是一个以迈阿…

IP风险画像在企业网络安全中应用

随着企业数字化的不断深入&#xff0c;网络安全问题日益突显。IP风险画像作为一种综合性的网络安全工具&#xff0c;为企业提供了更全面的风险评估和防范手段。本文将结合一个实际案例&#xff0c;深入探讨IP风险画像在企业网络安全中的成功应用。 案例背景 一家大型金融机构…

VS2019 添加程序包

dotnet add package AlibabaCloud.SDK.Bailian20230601 来提示添加程序包 选择菜单栏 项目----管理NuGet程序包 输入程序包的名称&#xff0c;然后添加即可&#xff0c; 这只是给当前工程添加&#xff0c;并不是给VS添加&#xff0c;所以你打开新工程&#xff0c;需要使用的话…

详解WebRTC rtc::Thread实现

rtc::Thread介绍 rtc::Thread类不仅仅实现了线程这个执行器&#xff08;比如posix底层调用pthread相关接口创建线程&#xff0c;管理线程等&#xff09;&#xff0c;还包括消息队列&#xff08;message_queue)的实现&#xff0c;rtc::Thread启动后就作为一个永不停止的event l…

【图论】基环树

基环树其实并不是树&#xff0c;是指有n个点n条边的图&#xff0c;我们知道n个点n-1条边的连通图是树&#xff0c;再加一条边就会形成一个环&#xff0c;所以基环树中一定有一个环&#xff0c;长下面这样&#xff1a; 由基环树可以引申出基环内向树和基环外向树 基环内向树如…

【开源】WordPress一键崩溃宕机插件(整活娱乐)

插件介绍 可一键实现Wordpress崩溃宕机的整活向插件&#xff08;请勿用于非法途径&#xff0c;仅供整活娱乐&#xff09;。鼓励关注网站性能的提升&#xff0c;以提供更好的用户体验&#xff0c;提倡为用户提供良好体验和高效速度的原则。 介绍 长期以来&#xff0c;人们都在…

WordPress从入门到精通【安装部署】

初识WordPress WordPress&#xff0c;简称WP&#xff0c;其简称的由来是取英文单词“word”与“press”的首字母 WP中文官网 1WP主站&#xff08;英文&#xff09; 官方标称&#xff0c;已有43%的网站在使用WordPress WordPress亮点 WP使用PHP语言开发&#xff0c;兼容性极…

深度学习/自动驾驶数据集大集合(目标检测/图像分割/语义分割/图像分类/)

深度学习和自动驾驶技术的发展离不开高质量的数据集&#xff0c;这些数据集对于训练和验证各种自动驾驶算法和模型起着至关重要的作用。深度学习/自动驾驶数据集大集合是一项汇集了多种场景、多种数据类型的数据资源&#xff0c;旨在为深度学习和自动驾驶领域的研究者和从业者提…

设计模式-行为型模式(上)

行为型模式用于描述程序在运行时复杂的流程控制&#xff0c;即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务&#xff0c;它涉及算法与对象间职责的分配。 行为型模式分为类行为模式和对象行为模式&#xff0c;前者采用继承机制来在类间分派行为&…

【服务器】RAID(独立磁盘冗余阵列)

RAID&#xff08;独立磁盘冗余阵列&#xff09; 一、RAID的介绍二、RAID的分类#2-1 RAID 02-2 RAID 1#2-3 RAID 32-4 RAID 52-5 RAID 62-6 RAID 10(先做镜像&#xff0c;再做条带化)2-7 RAID 01&#xff08;先做条带&#xff0c;再做镜像&#xff09;2-8 RAID比较 三、磁盘阵列…

CSDN文章导出工具

源码地址&#xff1a; github:https://github.com/lishuangquan1987/CSDNExportergitee:https://gitee.com/lishuangquan1987/csdnexporter 介绍 最近有CSDN博客导出来的需求&#xff0c;翻看了很多开源工具&#xff0c;都不能用或者不好用&#xff0c;于是决定自己做一个。…

机器学习6-逻辑回归

逻辑回归是机器学习中一种常用于二分类问题的监督学习算法。虽然名字中包含“回归”,但实际上它用于分类任务,特别是对于输出为两个类别的情况。逻辑回归通过使用 logistic 函数将输入映射到一个在0,1范围内的概率值,然后根据这个概率值进行分类。 以下是逻辑回归的基本概念…

线程池,定时器以及阻塞队列(生产者/消费者模型)

&#x1f493; 博客主页&#xff1a;从零开始的-CodeNinja之路 ⏩ 收录专栏&#xff1a;线程池,定时器以及阻塞队列(生产者/消费者模型) &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 实现线程池,定时器以及阻塞队列,生产者/消费者模型 线程池线程池…

c++用户管理信息(类指针数组)

用户管理信息--类指针数组 类示意图select类示意图MyIterator示意图VetorCstu示意图ClassStu示意图 项目源代码selectselect.hselect.cpp MyIteratorMyIterator.hMyIterator.cpp VetorCstuVetorCstu.hVetorCstu.cpp ClassStuClassStu.hClassStu.cpp main源码 总结---数组管理指…

中科大计网学习记录笔记(五):协议层次和服务模型

前言&#xff1a; 学习视频&#xff1a;中科大郑烇、杨坚全套《计算机网络&#xff08;自顶向下方法 第7版&#xff0c;James F.Kurose&#xff0c;Keith W.Ross&#xff09;》课程 该视频是B站非常著名的计网学习视频&#xff0c;但相信很多朋友和我一样在听完前面的部分发现信…

2024.2.4日总结(小程序开发1)

小程序开发和普通网页开发的区别 运行环境不同 网页运行在浏览器环境中&#xff0c;小程序运行在微信环境中 API不同 由于运行的环境不同&#xff0c;所以小程序中无法调用DCM和BOM的API&#xff0c;但是可以调用微信环境提供的各种API&#xff0c;如&#xff1a;地理定位&…

MySQL学习记录——삼 库的操作

文章目录 1、创建数据库2、字符集和校验集3、基本操作4、备份与恢复5、连接情况 1、创建数据库 开两个窗口&#xff0c;一个用来访问数据目录/var/lib/mysql&#xff0c;一个用来打开mysql&#xff1a;mysql -u root -p。 创建用的命令 create databse d1; d1是名字&#xff…

【Java八股文面试系列】JVM-内存区域

目录 Java内存区域 运行时数据区域 线程独享区域 程序计数器 Java 虚拟机栈 StackFlowError&OOM 本地方法栈 线程共享区域 堆 GCR-分代回收算法 字符串常量池 方法区 运行时常量池 HotSpot 虚拟机对象探秘 对象的创建 对象的内存布局 句柄 Java内存区域 运…

BUG:docker启动之后直接退出问题

示例如下&#xff1a; 问题排查&#xff1a; 启动命令 sudo docker run --privilegedtrue --runtimenvidia --shm-size80g -v /mmm_data_center:/mmm_data_center -v /imagecenter_new/:/imagecenter_new -v /data1:/data1 -v /mnt/offline_data/:/mnt/offline_data/ --neth…