Qt中的网络通信

news2024/10/7 14:29:00

C++没有封装专门的网络套接字的类,因此C++只能调用C对应的API,而在Linux和Windows环境下的API都是不一样的
Qt作为一个C++框架提供了相关封装好的套接字通信类
在Qt中需要用到两个类,两个类都属于network且都是属于IO操作,只不过这两个类是对网络传过来数据进行IO操作
使用前需要再.pro文件里添加 += network
QTcpServer 服务器类,用于监听客户端连接和与客户端创建连接
QTcpSocket 通信的套接字类,服务器和客户端都要使用

QTcpServer常用API

常用函数

构造函数

参数指定父对象,目的是利用Qt对象树机制

QTcpServer::QTcpServer(QObject *parent = nullptr)

给套接字设置监听

//第一个参数,绑定本地地址,默认是任意一个地址,使用时建议用默认值,代表自动绑定
//第二个参数是端口号
bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0)

//判断当前对象是否在监听,是返回true,否返回false
bool QTcpServer::isListening() const

//如果当前对象正在监听,返回监听的服务器地址信息否则返回QHostAddress::Null
QHostAddress QTcpServer::serverAddress() const

//如果当前对象正在监听,返回监听的服务器端口号,否则返回0
quint16 QTcpServer::serverPort() const

注:
1.listen函数的两个参数都有默认值,但是端口号必须由程序员指定,否则系统会随机绑定一个端口,这样就无法连接了。建议使用5000以上的端口

获取通信套接字

此函数会获得通信使用的套接字对象,这个对象是QTcpServer的子对象,当父对象被析构时,子对象也会被析构

QTcpSocket *QTcpServer::nextPendingConnection()

本函数是一个阻塞函数。当启动服务器线程后调用这个函数后就会阻塞服务器并等待客户端连接,直到客户端连接后解除阻塞,但是不推荐使用,建议使用信号

bool QTcpServer::waitForNewConnection(int msec = 0, bool *timedOut = nullptr)
  • 第一个参数设置最大阻塞时间,单位毫秒
  • 第二个参数是个传出参数true为超时解除阻塞,false为非超时解除阻塞

信号

[signal] void QTcpServer::newConnection()

每次有新连接时都会发出newConnection信号

[signal, since 5.0] void QTcpServer::acceptError(QAbstractSocket::SocketError socketError)

当接受新连接导致错误时,会发出acceptError信号,socketError参数描述了错误信息

QTcpSocket常用API

Qt读写网络上传过来的数据,本质上是对本地的数据进行读写,因为Qt会对接收的数据放入一块分配好的内存,然后对这块内存进行读写

常用函数

构造函数

QTcpSocket::QTcpSocket(QObject *parent = nullptr)

连接服务器,指定端口和IP地址等需要的信息
第一个参数是服务器地址(IP地址),第二个参数是服务器端口,服务器绑定了哪个端口就连接哪个端口,第三个参数是打开方式,第四个参数一般不做修改

[virtual] void QAbstractSocket::connectToHost(const QString &hostName, quint16 port, QIODeviceBase::OpenMode openMode = ReadWrite, QAbstractSocket::NetworkLayerProtocol protocol = AnyIPProtocol)

void QAbstractSocket::connectToHost(const QHostAddress &address, quint16 port, QIODeviceBase::OpenMode openMode = ReadWrite)

在这里插入图片描述
在这里插入图片描述

通信流程

在这里插入图片描述
在这里插入图片描述

网络通信发送文件与进度条处理

服务端

子线程文件

#include "recvfile.h"
#include <QFile>

RecvFile::RecvFile(QTcpSocket* tcp,QObject *parent)
    : QThread{parent}
{
    m_tcp = tcp;
}

void RecvFile::run()
{
    QFile *file = new QFile("recv.txt");
    file->open(QFile::WriteOnly);

    //接受数据
    connect(m_tcp,&QTcpSocket::readyRead,this,[=]()
    {
        static int count = 0;
        static int total = 0;
        if (count == 0)
        {
            m_tcp->read((char*)&total,4);
        }
        //读出剩余的数据
        QByteArray all = m_tcp->readAll();
        count += all.size();
        file->write(all);

        if (count == total)
        {
            m_tcp->close();
            m_tcp->deleteLater();
            file->close();
            file->deleteLater();
            emit over();
        }

    });
    //进入事件循环,要一直等有没有文件发过来
    exec();
}

主线程文件

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "recvfile.h"
#include <QMessageBox>
#include <QTcpSocket>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    qDebug() << "服务器主线程:" << QThread::currentThread();

    m_s = new QTcpServer(this);
    //有连接的信号槽处理
    connect(m_s,&QTcpServer::newConnection,this,[=](){
        QTcpSocket* m_tcp = m_s->nextPendingConnection();
        //创建子线程对象
        RecvFile* subThread = new RecvFile(m_tcp);
        subThread->start();

        connect(subThread,&RecvFile::over,this,[=](){
            subThread->quit();
            subThread->wait();
            subThread->deleteLater();
            QMessageBox::information(this,"信息","文件传输完毕");
        });
    });
}

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

void MainWindow::on_setListen_clicked()
{
    unsigned short port = ui->port->text().toUShort();
    m_s->listen(QHostAddress::Any,port);
}


客户端

工作类

#include "sendfile.h"
#include <QFile>
#include <QFileInfo>
#include <QHostAddress>

SendFile::SendFile(QObject *parent)
    : QObject{parent}
{}

void SendFile::connectToServer(unsigned short port, QString ip)
{
    m_socket = new QTcpSocket;
    //连接服务器
    m_socket->connectToHost(QHostAddress(ip),port);
    //检测服务器和客户端是否连接成功
    connect(m_socket,&QTcpSocket::connected,this,&SendFile::connetOK);
    //断开连接操作
    connect(m_socket,&QTcpSocket::disconnected,this,[=](){
        m_socket->close();
        m_socket->deleteLater();
        emit fileFinish();
    });

}

void SendFile::sendFile(QString path)
{
    //打开文件
    QFile file(path);

    //第一次发送时要获取文件大小
    QFileInfo info(path);
    //文件大小
    int fileSize = info.size();

    file.open(QFile::ReadOnly);
    //文件没读完就一直读
    while (!file.atEnd())
    {
        //第一次循环就发送文件大小
        static int num = 0;
        if (num == 0)
        {
            m_socket->write((char*)&fileSize,4);
        }
        QByteArray line = file.readLine();
        num += line.size();
        //计算当前的发送百分比
        int percent = num * 100 / fileSize;
        //发送对应用于进度条维护的信号
        emit curPercent(percent);
        //发送信息
        m_socket->write(line);

    }

}

主窗口

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QThread>
#include "sendfile.h"
#include <QMessageBox>
#include <QFileDialog>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //初始化端口,ip和进度条
    ui->ip->setText("127.0.0.1");
    ui->port->setText("8989");
    ui->progressBar->setRange(0,100);
    ui->progressBar->setValue(0);

    //创建线程对象
    QThread* t = new QThread;
    //创建任务对象
    SendFile* worker = new SendFile;
    //将任务移动到线程里
    worker->moveToThread(t);

    //发送信号告诉子线程什么时候连接服务器,什么时候发送文件
    connect(this,&MainWindow::startConnect,worker,&SendFile::connectToServer);
    connect(this,&MainWindow::sendFile,worker,&SendFile::sendFile);
    //处理子线程发出来的信号
    connect(worker,&SendFile::connetOK,this,[=](){
        QMessageBox::information(this,"连接服务器","服务器连接成功!");

    });

    //更新进度条处理
    connect(worker,&SendFile::curPercent,ui->progressBar,&QProgressBar::setValue);

    //文件发完了就释放资源
    connect(worker,&SendFile::fileFinish,this,[=](){
        //资源释放
        t->quit();
        t->wait();
        worker->deleteLater();
        t->deleteLater();
    });

    t->start();

}

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

void MainWindow::on_connect_clicked()
{
    QString ip = ui->ip->text();
    unsigned short port = ui -> port->text().toUShort();
    emit startConnect(port,ip);
}


void MainWindow::on_selFile_clicked()
{
    QString path = QFileDialog::getOpenFileName();
    if (path.isEmpty())
    {
        QMessageBox::warning(this,"警告","文件路径不能为空!");
        return;
    }
    ui->filePath->setText(path);
}


void MainWindow::on_sendFile_clicked()
{
    emit sendFile(ui->filePath->text());
}


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

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

相关文章

第十四届蓝桥杯C/C++大学B组题解(一)

1、日期统计 #include <bits/stdc.h> using namespace std; int main() {int array[100] {5, 6, 8, 6, 9, 1, 6, 1, 2, 4, 9, 1, 9, 8, 2, 3, 6, 4, 7, 7,5, 9, 5, 0, 3, 8, 7, 5, 8, 1, 5, 8, 6, 1, 8, 3, 0, 3, 7, 9,2, 7, 0, 5, 8, 8, 5, 7, 0, 9, 9, 1, 9, 4, 4, 6,…

Golang | Leetcode Golang题解之第8题字符串转换整数atoi

题目&#xff1a; 题解&#xff1a; func myAtoi(s string) int {abs, sign, i, n : 0, 1, 0, len(s)//丢弃无用的前导空格for i < n && s[i] {i}//标记正负号if i < n {if s[i] - {sign -1i} else if s[i] {sign 1i}}for i < n && s[i] >…

DFS序列

什么是DFS序 DFS序是指对一棵树进行DFS时&#xff0c;每个节点被访问到的顺序。DFS序分成两个部分&#xff1a;进入该节点的顺序和退出该节点的顺序。 如何求DFS序 对于DFS中当前节点 1&#xff1a;计数 2&#xff1a;进入当前节点的顺序等于当前计数 3&#xff1a;想所有…

阿里云可观测 2024 年 3 月产品动态

本月可观测热文回顾 文章一览&#xff1a; 全新架构&#xff01;日志服务 SLS 自研免登录方案发布 AIOps 智能运维&#xff1a;有没有比专家经验更优雅的错/慢调用分析工具&#xff1f; 一文看懂如何做好 SQL 质量监控 使用 SPL 高效实现 Flink SLS Connector 下推 功能快…

pandas用法-详解教程

pandas用法-详解教程 一、生成数据表二、数据表信息查看三、数据表清洗四、数据预处理五、数据提取六、数据筛选七、数据汇总八、数据统计九、数据输出 一、生成数据表 1、首先导入pandas库&#xff0c;一般都会用到numpy库&#xff0c;所以我们先导入备用&#xff1a; impor…

深度学习理论基础(六)Transformer多头注意力机制

目录 一、自定义多头注意力机制1. 缩放点积注意力&#xff08;Scaled Dot-Product Attention&#xff09;● 计算公式● 原理 2. 多头注意力机制框图● 具体代码 二、pytorch中的子注意力机制模块 深度学习中的注意力机制&#xff08;Attention Mechanism&#xff09;是一种模仿…

docker基础学习指令

文章目录 [toc] docker基础常用指令一、docker 基础命令二、docker 镜像命令1. docker images2. docker search3. docker pull4. docker system df5. docker rmi1. Commit 命令 三、 docker 容器命令1. docker run2. docker logs3. docker top4. docker inspect5. docker cp6. …

Mybatis报错:Unsupported conversion from LONG to java.sql.Timestamp

Mybatis在封装结果集的时候&#xff0c;如果方法返回的是对象&#xff0c;则会去调用这个对象的无参构造方法。 如果实体类标注了Builder注解&#xff0c;则此注解会把默认的构造方法全部改成私有的&#xff0c;则Mybatis在通过无参构造方法反射创建对象时&#xff0c;就会找不…

#QT项目实战(天气预报)

1.IDE&#xff1a;QTCreator 2.实验&#xff1a; 3.记录&#xff1a; &#xff08;1&#xff09;调用API的Url a.调用API获取IP whois.pconline.com.cn/ipJson.jsp?iphttp://whois.pconline.com.cn/ipJson.jsp?ip if(window.IPCallBack) {IPCallBack({"ip":&quo…

Python学习之-魔术方法

前言&#xff1a; Python 中的魔术方法&#xff08;Magic Methods&#xff09;&#xff0c;也称作特殊方法&#xff08;Special Methods&#xff09;&#xff0c;是那些被双下划线包围的方法&#xff0c;例如 init。这些方法在 Python 中有特殊的含义&#xff0c;它们并不需要…

ThingsBoard通过MQTT发送遥测数据

MQTT基础 客户端 MQTT连接 遥测上传API 案例 MQTT基础 MQTT是一种轻量级的发布-订阅消息传递协议&#xff0c;它可能最适合各种物联网设备。 你可以在此处找到有关MQTT的更多信息&#xff0c;ThingsBoard服务器支持QoS级别0&#xff08;最多一次&#xff09;和QoS级别1&…

程序猿成长之路之数据挖掘篇——频繁项集挖掘介绍

频繁项集挖掘可以说是数据挖掘中的重点&#xff0c;下面我们来分析以下频繁项集挖掘的过程和目标 如果对数据挖掘没有概念的小伙伴可以查看上次的文章 https://blog.csdn.net/qq_31236027/article/details/137046475 什么是频繁项集&#xff1f; 在回答这个问题之前&#xff…

蓝桥杯第101题 拉马车 C++ Java Python

目录 题目 思路和解题方法 复杂度: c 代码 Java 版本&#xff08;仅供参考&#xff09; Python 版本&#xff08;仅供参考&#xff09; 代码细节 C 版本: Java 版本: Python 版本: 题目 思路和解题方法 这个游戏是一个简单的纸牌游戏&#xff0c;两个玩家轮流出牌&am…

Springboot相关知识-图片描述(学习笔记)

学习java过程中的一些笔记&#xff0c;觉得比较重要就顺手记录下来了~ 目录 一、前后端请求1.前后端交互2.简单传参3.数组集合传参4.日期参数5.Json参数6.路径参数7.响应数据8.解析xml文件9.统一返回类10.三层架构11.分层解耦12.Bean的声明13.组件扫描14.自动注入 一、前后端请…

(免费分享)基于springboot,vue问卷调查系统

用户注册、用户登录、创建调查问卷、编辑问卷问题和选型&#xff08;支持题型&#xff1a;单选、多选、单行文本、多行文本、数字、评分、日期、文本描述&#xff09;、保存和发布问卷、停止问卷调查、游客填写调查问卷&#xff08;一个IP地址只能填写一次&#xff09; 技术&a…

4.3 IO day5

1&#xff1a;实现文件夹的拷贝功能 注意判断被拷贝的文件夹是否存在&#xff0c;如果不存在则提前创建&#xff0c;创建文件夹的函数为 mkdir 不考虑递归拷贝的问题 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h…

蓝桥杯刷题-09-三国游戏-贪心⭐⭐⭐

蓝桥杯2023年第十四届省赛真题-三国游戏 小蓝正在玩一款游戏。游戏中魏蜀吴三个国家各自拥有一定数量的士兵X, Y, Z (一开始可以认为都为 0 )。游戏有 n 个可能会发生的事件&#xff0c;每个事件之间相互独立且最多只会发生一次&#xff0c;当第 i 个事件发生时会分别让 X, Y,…

清明作业 c++

1.封装一个类&#xff0c;实现对一个数求累和阶乘质数 #include <iostream>using namespace std; int mproduct(int a){if(a>1){return a*mproduct((a-1));}else{return 1;} } class number{int a; public:number():a(5){};number(int a):a(a){}void set(int a){thi…

开源的页面生成器:拖拽即可生成小程序、H5页面和网站

星搭精卫 MtBird 是一款低代码可视化页面生成器&#xff0c;可以帮助用户以可视化的形式搭建网页、小程序和表单等应用。 使用这个生成器&#xff0c;不需要代码就可以生成小程序、H5页面和网站&#xff0c;拖拽操作、样式配置快速生成页面应用&#xff0c;数据可视化接入&…

2024年【道路运输企业安全生产管理人员】找解析及道路运输企业安全生产管理人员作业考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 道路运输企业安全生产管理人员找解析参考答案及道路运输企业安全生产管理人员考试试题解析是安全生产模拟考试一点通题库老师及道路运输企业安全生产管理人员操作证已考过的学员汇总&#xff0c;相对有效帮助道路运输…