Qt网络通信

news2025/1/10 1:59:20

1. UDP通信

1.1 udp通信的基本流程

创建套接字

绑定套接字

进行通信

关闭套接字

涉及到的类和信号

QUdpSocket:Udp套接字类,类对象就是一个udp套接字对象
QHostAddress:ip地址类
void readyRead():信号,当有数据到达可读,就会产生这个信号

1.2 举例

通信端1

udp1

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QUdpSocket>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void on_pushButton_clicked();

    //当有数据到达时的槽
    void readdate();
private:
    Ui::Widget *ui;

    //创建udp对象
    QUdpSocket* socket;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

//udp通信
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //1. 创建udp套接字
    socket = new QUdpSocket;

    //2. 绑定
    //ip地址类,直接构造设置ip地址
    QHostAddress addr("192.168.124.33");
    //addr.setAddress();//函数设置ip地址
    socket->bind(addr,10000);


    //绑定readyRead信号,当有数据到达时,就会触发信号,去接收数据
    connect(socket,SIGNAL(readyRead()),this,SLOT(readdate()));

}

Widget::~Widget()
{
    delete ui;
}

//发送数据
void Widget::on_pushButton_clicked()
{
    //发送数据
    //定义缓冲区
    QByteArray data = ui->textEdit_2->toPlainText().toLocal8Bit();//toLocal8Bit()将数据转换为QByteArray类型
    socket->writeDatagram(data,QHostAddress("192.168.124.33"),10001);
}

//接收数据
void Widget::readdate(){

    //定义缓冲区
    QByteArray data;
    data.resize(1024);

    //读发来的数据存,储到data中
    QHostAddress addr;
    quint16 port;
    //size是收到的数据大小
    int size = socket->readDatagram(data.data(),data.size(),&addr,&port);//参数addrr,port是发送方的ip和端口

    data.resize(size);

    //展示数据
    ui->textEdit->append("发送端的ip:"+addr.toString()+"  port:"+QString::number(port));
    ui->textEdit->append(data);
}


通信端2

udp2

widget.h

widget.cpp

运行

2. TCP通信

2.1 客户端通信流程 QTcpSocket

1. 创建套接字

2. 绑定套接字

3. 连接服务器

4. 进行通信

5. 关闭套接字

2.1.1 涉及的信号 

connected():信号,当连接服务器且连接成功

readyRead():信号,当发送给数据到套接字,套接字可读

disconnected():信号,只要套接字断开连接,就会产生

2.2 服务端通信流程 QTcpServer

1. 创建套接字

2绑定套接字

3监听套接字---套接字类型改变改为监听套接字

4连接客户端---得到与客户端进行通信的套接字

5进行通信

6关闭套接字

相关函数

nextPendingConnection():服务器建立与客户端连接,返回值 QTcpScket 类对象:通信套接字对象

2.2.1 涉及的信号

newConnection():信号,当有新的客户端连接时,会产生这个信号

readyRead():信号,当发送给数据到套接字,套接字可读

disconnected():信号,只要套接字断开连接,就会产生

2.2 举例:模拟客户端和服务端通信

2.2.1 客户端

tcp_client

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpSocket>
#include <QHostAddress>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void on_pushButton_connect_clicked();

    //当连接服务器,且连接成功的槽
    void socket_conn();

    void on_pushButton_send_clicked();

    //当有数据发来时,触发该信号
    void readdata();

    void on_pushButton_duankai_clicked();

    //当连接断开,触发该信号
    void socket_disconn();

private:
    Ui::Widget *ui;

    //创建tcp对象
    QTcpSocket* socket;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"


//tcp通信客户端
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //1.创建套接字对象
    socket = new QTcpSocket;

    //2.绑定,这里其实可以不用绑定,系统会自动给你分配
    socket->bind(QHostAddress("192.168.124.33"),9999);

    //设置连接按钮可点击,发送和点击不可点
    ui->pushButton_connect->setEnabled(true);
    ui->pushButton_send->setEnabled(false);
    ui->pushButton_duankai->setEnabled(false);

}

Widget::~Widget()
{
    delete ui;
}


//连接服务器
void Widget::on_pushButton_connect_clicked()
{
    //3. 连接服务器,参数1服务端ip,参数2服务端端口
    socket->connectToHost(ui->lineEdit_ip->text(),ui->lineEdit_port->text().toUShort());//toUShort() 字符串转为数字


    //提示,注意这里的信号和槽的绑定写在连接按钮里,后面会有个问题,就是每连接一次信号和槽都会再绑定一次,造成多次重复绑定
    //要解决问题,就需要在断开连接哪里把绑定的信号和槽断开
    //如果把信号和槽的绑定写在上面的构造里就不会有这个问题了
    
    //当连接服务器,且连接成功,就会触发该信号
    connect(socket,SIGNAL(connected()),this,SLOT(socket_conn()));

    //当有数据发来时,触发该信号
    connect(socket,SIGNAL(readyRead()),this,SLOT(readdata()));

    //当连接断开,触发该信号
    connect(socket,SIGNAL(disconnected()),this,SLOT(socket_disconn()));
}

//当连接服务器,且连接成功,触发的信号对应的槽
void Widget::socket_conn(){
    //接收框里提示连接成功
    ui->textEdit_receice->append(ui->lineEdit_ip->text()+":"+ui->lineEdit_port->text()+"  connect ok");

    //设置连接按钮不可点击,断开和发送可点击
    ui->pushButton_connect->setEnabled(false);
    ui->pushButton_send->setEnabled(true);
    ui->pushButton_duankai->setEnabled(true);
}


//点击发送数据给服务器
void Widget::on_pushButton_send_clicked()
{
    //4.将数据发送给服务器
    //toStdString().c_str()先转为c++标准字符串,再转为c字符串
    socket->write(ui->textEdit_write->toPlainText().toStdString().c_str());

}

//当有数据发来时,接收数据
void Widget::readdata(){
    //5.读取数据
    QByteArray data =  socket->readAll();
    ui->textEdit_receice->append(data);
}


//客户端断开与服务器的连接
void Widget::on_pushButton_duankai_clicked()
{
    //6.断开与服务端的连接
    socket->disconnectFromHost();

}

//连接断开后要做到处理  对应的槽(只要连接断开就会进入这个槽函数)
void Widget::socket_disconn(){
    //接收框里提示连接断开
    ui->textEdit_receice->append(ui->lineEdit_ip->text()+":"+ui->lineEdit_port->text()+"  disconnect");

    //把绑定的信号和槽断开
    disconnect(socket,SIGNAL(connected()),this,SLOT(socket_conn()));
    disconnect(socket,SIGNAL(readyRead()),this,SLOT(readdata()));
    disconnect(socket,SIGNAL(disconnected()),this,SLOT(socket_disconn()));

    //设置连接按钮可点击,发送和点击不可点
    ui->pushButton_connect->setEnabled(true);
    ui->pushButton_send->setEnabled(false);
    ui->pushButton_duankai->setEnabled(false);
}

测试使用网络调试助手E:\peixunqianrushi_ziliao\网络调试助手

连接

发送数据

点击断开连接

2.2.2 服务端

服务器设置为多线程---并发服务器,每个客户端在线程中进行操作

tcp_server

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <thread_tcp.h>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void on_pushButton_start_clicked();

    //当有新的客户端连接时的槽
    void new_conn_arrive();

    void on_pushButton_end_clicked();

private:
    Ui::Widget *ui;

    //实例化tcp对象
    QTcpServer* server;

    //存储的socket就是与客户端的通信套接字
    QTcpSocket* socket1;

    //存储所有的通信套接字
    QList<QTcpSocket*> list;

};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"


//tcp通信服务端
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //1.创建tcp服务端套接字
    server = new QTcpServer;

    //2.绑定,这里提示,在qt中绑定和监听写在一起了,都在listen函数中

    //当有新的客户端连接时,就会触发该信号
    connect(server,SIGNAL(newConnection()),this,SLOT(new_conn_arrive()));

}

Widget::~Widget()
{
    delete ui;
}


//启动服务器
void Widget::on_pushButton_start_clicked()
{
    //3.监听,这里提示,在qt中绑定和监听写在一起了
    server->listen(QHostAddress("192.168.124.33"),8888);
    ui->textEdit->append("服务器启动成功~~~");

}


//当有新的客户端连接请求时,触发该信号对应的槽函数
//建立连接
void Widget::new_conn_arrive(){

    //4.服务器建立与客户端的连接
    //现在的socket1就是与客户端的通信套接字
    socket1 = server->nextPendingConnection();
    //提示客户端连接成功
    socket1->write("connect success~~~~~~~");
    //将通信套接字添加进链表
    list.append(socket1);


    //从这里使用线程
    //把与客户端通信的套接字,放入线程中,使用线程来操作套接字与客户端通信
    //创建线程,有一个客户端就创建一个线程
    thread_tcp* tcp = new thread_tcp;
    //把通信套接字给线程
    tcp->socket = socket1;

    //当客户端发来消息,就会触发 在线程中的 写的槽函数,去读取客户端消息
    connect(tcp->socket,SIGNAL(readyRead()),tcp,SLOT(readdata()));

    //客户端断开连接,触发信号调用 线程中的槽,使线程关闭
    connect(tcp->socket,SIGNAL(disconnected()),tcp,SLOT(dis_conn()));


    //启动线程
    tcp->start();

}


//关闭服务器
void Widget::on_pushButton_end_clicked()
{
    for(int i=0;i<list.size();i++){
        //服务端关闭通信套接字的连接
        list.at(i)->disconnectFromHost();
    }

    list.clear();

    //关闭监听
    server->close();

    ui->textEdit->append("服务端已经关闭连接~~~~~~~");
}


thread_tcp.h

#ifndef THREAD_TCP_H
#define THREAD_TCP_H

#include <QThread>
#include <QTcpSocket>
#include <QDebug>

class thread_tcp : public QThread
{
    Q_OBJECT
public:
    thread_tcp();

    //socket就是与客户端的通信套接字
    QTcpSocket* socket;

    //执行线程的run
    void run();


public slots:
    //当客户端发来消息的槽
    void readdata();

    //只要客户端断开,就关闭线程
    void dis_conn();

};

#endif // THREAD_TCP_H

thread_tcp.cpp

#include "thread_tcp.h"

thread_tcp::thread_tcp()
{

}

//当客户端发来消息,读数据
void thread_tcp::readdata(){

    //读出数据
    QByteArray data = socket->readAll();

    //给客户端返回数据
    socket->write(data);

}

//一直执行线程
void thread_tcp::run(){
    qDebug()<<"线程执行";
    //阻塞执行
    exec();
}

//客户端断开连接时,关闭线程
void thread_tcp::dis_conn(){
    qDebug()<<"线程关闭";
    exit(0);
}

测试

运行服务端

启动客户端和网络调试助手,分别充当两个客户

分别连接,成功

发送数据,成功

分别断开连接,成功

再次分别连接,测试服务端关闭功能

关闭成功

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

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

相关文章

码住!软件测试人员的基本有哪些?

在软件测试领域&#xff0c;许多人误以为软件测试只是简单的点点鼠标、看看屏幕就能完成。然而&#xff0c;软件测试的复杂性远不止于此。作为一名软件测试人员&#xff0c;你需要具备多项技能和素质来保证测试的有效性和质量。 打字技能可以事半功倍 打字是软件测试人员必备的…

2024年网络安全比赛--内存取证(超详细)

一、竞赛时间 180分钟 共计3小时 二、竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 1.从内存文件中找到异常程序的进程&#xff0c;将进程的名称作为Flag值提交&#xff1b; 2.从内存文件中找到黑客将异常程序迁移后的进程编号&#xff0c;将迁移后的进程编号作为Flag值…

能做鬼脸、摇滚、自拍,听懂你说的话!GPT-4驱动的实体机器人

东京大学的研究人员将GPT-4模型&#xff0c;集成在实体机器人Alter3中&#xff0c;可将文本、语言直接转化成机器人动作&#xff0c;例如&#xff0c;做一个自拍动作&#xff1b;装一个“鬼样”&#xff1b;做一个摇滚音乐动作等&#xff0c;就连微笑、眨眼这样的面部表情动作也…

IOS-UIAlertController简单使用-Swift

UIAlertControlle时IOS的对话框控制器&#xff08;警报控制器&#xff09;&#xff0c;简单使用方法如下&#xff1a; 步骤都一样&#xff0c;先是创建UIAlertController&#xff0c;然后创建UIAlertAction&#xff0c;再将UIAlertAction添加到UIAlertController中&#xff0c;…

SpringBoot项目中添加证书授权认证

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、项目场景二、方案思路三、实施流程1.引入库2.编写代码 四、拓展 一、项目场景 在上线的项目中&#xff0c;需要添加一个定时授权的功能&#xff0c;对系统的进…

Springboot 子工程构建完后无法找到springboot依赖

问题: 构建完子工程后无法找到SpringBootTest 解决方案: 最好用这个构建 https://www.cnblogs.com/he-wen/p/16735239.html 1.先观察项目目录 是否正确 2.观察子工程目录 3.看pom.xml中是否引用springboot依赖 4.检查代码 查看父项目是否包含子模块 查看子模块的父项目是否…

OB SQL引擎和存储引擎

文章目录 一 SQL引擎1.1 双模共存1.2 基本操作1.3 查看SQL的执行计划 二 存储引擎2.1 传统数据库存在的问题2.2 LSM-Tree存储2.3 OceanBase转储和合并2.4 控制内存数据落盘2.5 LSMTree存储压缩 三 备份恢复3.1 物理备份系统架构3.2 物理恢复系统架构 一 SQL引擎 1.1 双模共存 …

网安-入门永恒之蓝/黑

永恒之蓝 实验环境&#xff1a;win7&#xff0c;kali 实验目的&#xff1a;拿到win7管理员权限 扫描该网段 nmap -sP 192.168.164.0/24&#xff0c;查看win7ip&#xff0c;也可在win7上查询 扫描端口&#xff0c;445&#xff0c;永恒之蓝是通过445端口进行攻击的 masscan -…

个人网站制作 Part 8 添加电子邮件通知与社交媒体集成 | Web开发项目

文章目录 &#x1f469;‍&#x1f4bb; 基础Web开发练手项目系列&#xff1a;个人网站制作&#x1f680; 添加电子邮件通知&#x1f528;使用Nodemailer&#x1f527;步骤 1: 安装Nodemailer &#x1f680; 社交媒体集成&#x1f528;使用社交媒体API&#x1f527;步骤 2: 集成…

多输入多输出 | Matlab实现基于LightGBM多输入多输出预测

多输入多输出 | Matlab实现基于LightGBM多输入多输出预测 目录 多输入多输出 | Matlab实现基于LightGBM多输入多输出预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Matlab实现基于LightGBM多输入多输出预测&#xff08;完整源码和数据&#xff09; 1.data为数据集&a…

使用企业订货软件的担忧与考虑|网上APP订货系统

使用企业订货软件的担忧与考虑|网上APP订货系统 网上订货系统担心出现的问题 1&#xff0c;如果在订货系统中定错(多)货物了该怎么办 其实这也是很多人在网购或者是现实中经常会犯的一个错误&#xff0c;但是网上订货平台为大家提供了很多的解决方案&#xff0c;其中对于订单的…

腾讯云 腾讯云服务器 - 腾讯云 产业智变·云启未来

腾讯云服务器CVM提供安全可靠的弹性计算服务&#xff0c;腾讯云明星级云服务器&#xff0c;弹性计算实时扩展或缩减计算资源&#xff0c;支持包年包月、按量计费和竞价实例计费模式&#xff0c;CVM提供多种CPU、内存、硬盘和带宽可以灵活调整的实例规格&#xff0c;提供9个9的数…

jmeter-线程数设置为1,循环10次没问题,循环100次出现异常

一、多次尝试&#xff0c;发现出现异常的接口大致相同。 解决办法&#xff1a;在第一个出现异常的接口下添加超时时间&#xff0c;固定定时器&#xff1a;2000ms&#xff0c;再次运行就没问题了。 二、压力机自身存在的问题 1&#xff09;在网络编程中&#xff0c;特别是在短…

IOS-数据持久化UserDefaults简单使用-Swift

UserDefaults通过key-value的一种持久化方案&#xff0c;以键值对的形式存储基本类型数据&#xff0c;类似与安卓的SharePreferences。 使用方式&#xff0c;首先就是要获取standerd let userDefaultUserDefaults.standard存取字符串 //存取字符串 var greeting "Hello…

一款 StarRocks 客户端工具,支持可视化建表、数据编辑

什么是 StarRocks&#xff1f; StarRocks 是新一代极速全场景 MPP (Massively Parallel Processing) 数据库。StarRocks 的愿景是能够让用户的数据分析变得更加简单和敏捷。用户无需经过复杂的预处理&#xff0c;就可以用 StarRocks 来支持多种数据分析场景的极速分析。 为了…

循环异步调取接口使用数组promiseList保存,Promise.all(promiseList)获取不到数组内容,then()返回空数组

在使用 vue vant2.13.2 技术栈的项目中&#xff0c;因为上传文件的接口是单文件上传&#xff0c;当使用批量上传时&#xff0c;只能循环调取接口&#xff1b;然后有校验内容&#xff1a;需要所有文件上传成功后才能保存&#xff0c;在文件上传不成功时点击保存按钮&#xff0c…

django电影推荐系统

电影推荐 启动 ./bin/pycharm.shdjango-admin startproject movie_recommendation_projectcd movie_recommendation_project/python manage.py movie_recommendation_apppython manage.py startapp movle_recommendation_applspython manage.py runserver Using the URLconf d…

CSS||引入方式

目录 CSS引入方式 行内样式表&#xff08;行内式&#xff09; 内部样式表&#xff08;嵌入式&#xff09; 外部样式表&#xff08;链接式&#xff09; 引入外部样式表 CSS引入方式 CSS&#xff08;层叠样式表&#xff09;是一种用来描述文档样式的样式表语言&#xff0c;它…

【备战蓝桥杯】探索Python内置标准库collections的使用

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-q0zvWxZtAIdSGZ8R {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

高密数据中心卓越运维,更灵活助力企业 AI 就绪

AIGC的高速发展将企业对基础架构的需求推上了新的层次&#xff0c;根据中国通服数字基建产业研究院发布的《中国数据中心产业发展白皮书&#xff08;2023&#xff09;》报告&#xff0c;互联网行业客户对单机柜功率密度的要求较高&#xff0c;一般在6-8kW&#xff0c;金融行业处…