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

前言

今天分享一个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的工程文件以及一个别人写好的网络调试助手。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HACKTHEBOX通关笔记——Cronos(退役)

开启环境&#xff0c;调试网络确保互联互通 拿到IP之后还是先来做一下端口扫描&#xff0c;nmap --rate-min5000 -p- -v ip&#xff0c;也可以加个-Pn做下禁ping扫描&#xff0c;当然这个速率很快&#xff0c;实际攻防时候加了pn参数也是容易被发现的&#xff0c;所以对抗时候…

TypeScript实战系列之强力爆破泛型的困扰

目录 介绍开始如何理解泛型语法泛型约束泛型默认值练习后续 介绍 泛型在typescript 中使用频率相当高&#xff0c;也给了初学者相当大的阻碍。希望这一篇文章&#xff0c;能帮助你们爆破它。 开始 下面通过模拟实现一个简易版本的axios来引入泛型的使用 // axios.ts type M…

【面试】冲刺春招!每天三十道面试题——Java基础篇(一)

目录 一 JDK 和 JRE 的区分 二 简述编码的作用以及记事本的实现原理 三 基本类型有哪些&#xff1f;分别占据多少空间&#xff1f; 四 java中布尔类型的空间大小是怎么定下来的&#xff1f;为什么不是1bit&#xff0c; 把考虑因素说一下 五 int类型和float类型哪一个精度更…

算法学习——华为机考题库5(HJ31 - HJ35)

算法学习——华为机考题库5&#xff08;HJ31 - HJ35&#xff09; HJ31 单词倒排 描述 对字符串中的所有单词进行倒排。 说明&#xff1a; 1、构成单词的字符只有26个大写或小写英文字母&#xff1b; 2、非构成单词的字符均视为单词间隔符&#xff1b; 3、要求倒排后的单…

使用yolov5时需要安装的requirements.txt

之前需要配置好pytorch&#xff0c;同时注意的是pytoorch版本需要在1.7以上 1.github下载好requirements.txt 文件内容如下&#xff1a; 2.在cmd命令行转移到yolov5所在文件夹及配置的yolo环境中&#xff0c;直接下载 pip install -r requirements.txt -i http://pypi.doub…

ElementUI Form:Form表单

ElementUI安装与使用指南 Form表单 点击下载learnelementuispringboot项目源码 效果图 el-form.vue&#xff08;Form表单&#xff09;页面效果图 项目里 el-form.vue代码 <script> export default {name: el_form,data() {var checkAge (rule, value, callback…

计算机速成课Crash Course - 28. 计算机网络

今天继续计算机速成课Crash Course的系列讲解。 更多技术文章&#xff0c;全网首发公众号 “摸鱼IT” 锁定 -上午11点 - &#xff0c;感谢大家关注、转发、点赞&#xff01; 计算机速成课Crash Course - 28. 计算机网络 (qq.com) 28. 计算机网络 互联网太棒啦&#xff0c;键…

uptrained的解释

问题来源 language model checkpoints with multihead attention (MHA) can be uptrained (Komatsuzaki et al., 2022) to use MQA with a small fraction of original training compute 而翻译词典无法翻译 解释&#xff1a; “uptrained” 这个词没有直接的中文翻译&…

k8s学习-Kubernetes的包管理器Helm

1.1 为何需要Helm Kubernetes能够很好地组织和编排容器&#xff0c;但它缺少⼀个更高层次的应用打包工具&#xff0c;而Helm就是来干这件事的。 先来看个例子。 比如对于⼀个MySQL服务&#xff0c;Kubernetes需要部署下面这些对象&#xff1a; &#xff08;1&#xff09;Serv…

【遥感入门系列】遥感电磁辐射与遥感过程

遥感电磁辐射是比较难理解也是非常重要的内容&#xff0c;对于一般学习遥感专业的人来说&#xff0c;只需要学习个大概&#xff0c;这个大概主要包括你需要理解几个概念以及能从电磁辐射原理上解释一些遥感现象&#xff0c;进而为遥感过程的理解打下一个基础&#xff0c;如果你…

揭秘备忘录模式:打造灵活高效的状态管理解决方案

备忘录模式&#xff08;Memento Pattern&#xff09;是一种行为设计模式&#xff0c;它允许在不暴露对象内部状态的情况下捕获和恢复对象的内部状态。这种模式主要用于实现撤销操作。 在 Java 中&#xff0c;备忘录模式通常包括以下三个角色&#xff1a; 发起人&#xff08;O…

使用Java实现基于HTTP的分布式系统:让你的应用“四处开花”

在数字世界里&#xff0c;分布式系统就像是一个大家庭&#xff0c;每个成员&#xff08;即节点&#xff09;都有自己的任务和职责&#xff0c;共同维护整个家庭的运转。如果你想使用Java来实现这样一个大家庭&#xff0c;让应用在各个节点上“四处开花”&#xff0c;那就需要借…

设计模式1-访问者模式

访问者模式是一种行为设计模式&#xff0c;它允许你定义在对象结构中的元素上进行操作的新操作&#xff0c;而无需修改这些元素的类。这种模式的主要思想是将算法与元素的结构分离开&#xff0c;使得可以在不修改元素结构的情况下定义新的操作。 所谓算法与元素结构分离&#x…

css1文本属性

一.颜色&#xff08;color&#xff09;&#xff08;一般用16进制&#xff09; 二.对齐&#xff08;text-align) 三.装饰&#xff08;text-decoration&#xff09; 四.缩进&#xff08;text-indent&#xff09;&#xff08;一般用2em&#xff09;&#xff08;有单位&#xff09;…

面试数据结构与算法总结分类+leetcode目录【基础版】

&#x1f9e1;&#x1f9e1;&#x1f9e1;算法题目总结&#xff1a; 这里为大家总结数据结构与算法的题库目录&#xff0c;如果已经解释过的题目会标注链接更新&#xff0c;方便查看。 数据结构概览 Array & String 大家对这两类肯定比较清楚的&#xff0c;同时这也是面试…

idea中找到所有的TODO

idea中找到所有的TODO &#xff08;1&#xff09;快捷键 Alt6 &#xff08;2&#xff09;View -> Tool Windows -> TODO

【Chrono Engine学习总结】1-安装配置与程序运行

本文仅用于个人安装记录。 官方安装教程 https://api.projectchrono.org/8.0.0/tutorial_install_chrono.html Windows下安装 windows下安装就按照教程好了。采用cmake-gui进行配置&#xff0c;建议首次安装只安装核心模块。然后依此configure下irrlicht&#xff0c;sensor…

正则表达式可视化工具regex-vis

什么是正则表达式 &#xff1f; 正则表达式是对字符串操作的一种逻辑公式&#xff0c;就是用事先定义好的一些特定字符、及这些特定字符的组合&#xff0c;组成一个“规则字符串”&#xff0c;这个“规则字符串”用来表达对字符串的一种过滤逻辑。【百度百科】 正则表达式用简短…

python 视频硬字幕去除 内嵌字幕去除工具vsr

项目简介 开源地址&#xff1a;https://github.com/YaoFANGUK/video-subtitle-remover Video-subtitle-remover (VSR) 是一款基于AI技术&#xff0c;将视频中的硬字幕去除的软件。 主要实现了以下功能&#xff1a; 无损分辨率将视频中的硬字幕去除&#xff0c;生成去除字幕后…

《学成在线》微服务实战项目实操笔记系列(P1~P49)【上】

《学成在线》项目实操笔记系列【上】&#xff0c;跟视频的每一P对应&#xff0c;全系列12万字&#xff0c;涵盖详细步骤与问题的解决方案。如果你操作到某一步卡壳&#xff0c;参考这篇&#xff0c;相信会带给你极大启发。同时也欢迎大家提问与讨论&#xff0c;我会尽力帮大家解…