Qt 网络编程

news2024/11/26 6:00:49

QT 网络编程

TCP 编程

模块引入

QT += network

在这里插入图片描述

头文件

#include <QTcpServer> // TCP服务器端使用
#include <QTcpSocket> // TCP服务器和客户端都使用

编程流程

服务端

1)实例化 QTcpServer 对象 -----------------------------> socket
2)进入监听状态 ----> listen(QTcpServer类) // 不需要再绑定了----------->bind + listen
3)监测客户端连接 ---- newConnection 信号(QTcpServer类)
----------------> 有新连接过来,server 就能收到 newConnection 信号
4)QTcpSocket *client <---- 获得连接 ---- nextPendingConnection(QTcpServer类) ---->accept
5)连接对端接收信号 ------ readyRead(QTcpSocket类)
---------------------->如果对端有数据发送,server 就能收到 readyRead 信号
6)读取客户端消息 ------ readAll(QTcpSocket类) --------------------------> recv:读取数据
7)发送数据 ------ write(QTcpSocket类) ----> send:发数据
8)关闭连接 ------ disconnectFromHost() -------------------> close
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

客户端

1)实例化 QTcpSocket 对象;
2)连接服务器 ------ connectToHost ------> 接下来使用 waitForConnected 来判断是否连接成功
3)连接对端接收信号 ------ readyRead 信号
4)发送数据 ------ write()
5)关闭连接 ------ disconnectFromHost()
在这里插入图片描述
在这里插入图片描述

💡 客户端实现

widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QtWidgets>
#include <QTcpSocket>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
    void on_connectBtn_clicked();
    void recvSlot();

    void on_sendBtn_clicked();
//    void whetherConnectedSlot();		// 判断是否连接成功,方法二

private:
    Ui::Widget *ui;
    QTcpSocket *client;
    bool flag;
};

#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle("客户端");

    client = new QTcpSocket(this);
    QObject::connect(client, SIGNAL(readyRead()), this,  SLOT(recvSlot()));

// 判断是否连接成功,方法二
//    QObject::connect(client, SIGNAL(connected()), this,  SLOT(whetherConnectedSlot()));
}

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

// void Widget::whetherConnectedSlot()			// 判断是否连接成功,方法二
// {
//     flag = true;
// }

void Widget::on_connectBtn_clicked()
{
    client->connectToHost(ui->ipEdit->text(), ui->portEdit->text().toShort());

	// 判断是否连接成功,方法一
    if (!client->waitForConnected(1000))           
    {
        qDebug() << "Failed to connect. ";
        return ;
    }
    qDebug() << "Connected successfully! ";
    ui->connectBtn->setText("断开");
}

void Widget::recvSlot()
{
    QByteArray buffer = client->readAll();
    ui->recvEdit->setText(QString::fromLocal8Bit(buffer));
}

void Widget::on_sendBtn_clicked()
{
    QString buffer = ui->sendEdit->toPlainText();
    client->write(buffer.toLocal8Bit());
}

在这里插入图片描述

💡 服务器实现

widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QtWidgets>
#include <QTcpServer>
#include <QTcpSocket>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
    void on_connectBtn_clicked();
    void connectSlot();
    void recvSlot();

    void on_sendBtn_clicked();

private:
    Ui::Widget *ui;
    QTcpServer *server;
    QTcpSocket *client;
};

#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"

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

    server = new QTcpServer(this);
    this->setWindowTitle("服务器");

    // 这个信号触发,代表有客户端连接
    QObject::connect(server, SIGNAL(newConnection()), this,  SLOT(connectSlot()));
}

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

void Widget::on_connectBtn_clicked()
{
    // 监听是否有客户端连入,不阻塞等待
    if (!server->listen(QHostAddress::Any, ui->portEdit->text().toUShort()))
    {
        qDebug() << "Failed to listen. ";
        return ;
    }
    ui->connectBtn->setText("关闭");
}

void Widget::connectSlot()
{
    // 接受新的客户端连接
    client = server->nextPendingConnection();
    if (client == 0)
    {
        qDebug() << "There are no pending connections. ";
        return ;
    }

    // 一定要等到接受连接后,再去做客户端的信号连接
    QObject::connect(client, SIGNAL(readyRead()), this,  SLOT(recvSlot()));
}

void Widget::recvSlot()
{
    QByteArray buffer = client->readAll();
    // 编码转换:对方必须按照 GBK 格式发送
    ui->recvEdit->setText(QString::fromLocal8Bit(buffer));
}

void Widget::on_sendBtn_clicked()
{
    QString buffer = ui->sendEdit->toPlainText();	// 从textEdit中获取的内容一定是utf8编码
    client->write(buffer.toLocal8Bit());
}

在这里插入图片描述

💡 服务器与客户端交互

在这里插入图片描述

UDP 编程

模块引入

QT += network

在这里插入图片描述

头文件

#include

编程流程

1)实例化 QUdpSocket 对象 ------------------------------------------> socket
2)绑定地址、端口 ------ bind(QHostAddress::LocalHost,8888) -----> bind
3)收发报文 ------ readDatagram、writeDatagram ------------------> recvfrom/sendto
在这里插入图片描述

// 类和接口
bool 	QUdpSocket::hasPendingDatagrams() const;
qint64 	QUdpSocket::readDatagram(char * data, qint64 maxSize, QHostAddress * address = 0, quint16 * port = 0);
qint64 	QUdpSocket::writeDatagram(const char * data, qint64 size, const QHostAddress & address, quint16 port);

实现一个聊天功能,使用 UDP 通信。首先通过一个登录界面,输入服务器的 IP 和端口,点击登录后,将 IP 和端口传到聊天界面,然后通过 UDP 进行聊天(服务器)。

💡 服务器实现

在这里插入图片描述

chatpage.h
#ifndef CHATPAGE_H
#define CHATPAGE_H

#include <QtWidgets>
#include <QUdpSocket>
#include "globalvalue.h"

namespace Ui {
class ChatPage;
}

class ChatPage : public QWidget
{
    Q_OBJECT

public:
    explicit ChatPage(QWidget *parent = 0);
    ~ChatPage();

private:
    Ui::ChatPage *ui;

    QUdpSocket *socket;
    QHostAddress sender;        // 定义对端的地址,以便后续发送使用
    quint16 senderPort;

private slots:
    void readPendingDatagrams();
    void on_sendBtn_clicked();
};

#endif // CHATPAGE_H
chatpage.cpp
#include "chatpage.h"
#include "ui_chatpage.h"

ChatPage::ChatPage(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ChatPage)
{
    ui->setupUi(this);
    this->setWindowTitle("聊天");

    // 初始化一个 QUdpSocket 对象
    socket = new QUdpSocket(this);

    // 绑定服务器的地址和IP,客户端省略此句
    socket->bind(QHostAddress(GlobalValue::ipaddr), GlobalValue::port);

    connect(socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
}

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

void ChatPage::readPendingDatagrams()
{
    // 如果udp缓冲区有报文数据的话
    while (socket->hasPendingDatagrams())
    {
        QByteArray datagram;    // 初始化一个字节流缓冲区
        datagram.resize(socket->pendingDatagramSize());		// 重设缓冲区的大小

        socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
        // 对方发送的字节流必须是GBK编码
        ui->recvEdit->setText(QString::fromLocal8Bit(datagram));
    }
}
void ChatPage::on_sendBtn_clicked()
{
    // 如果已经接收过消息,那么sender和senderPort已经有对方的地址了
    socket->writeDatagram(ui->sendEdit->toPlainText().toLocal8Bit(), sender, senderPort);
}

在这里插入图片描述

globalvalue.h
#ifndef GLOBALVALUE_H
#define GLOBALVALUE_H

#include <QString>

class GlobalValue           // 此类仅用于存放静态变量
{
public:
    GlobalValue();

    static QString ipaddr;
    static quint16 port;
};

#endif // GLOBALVALUE_H
globalvalue.cpp
#include "globalvalue.h"

QString GlobalValue::ipaddr;
quint16 GlobalValue::port;

GlobalValue::GlobalValue()
{
}
userver.h
#ifndef USERVER_H
#define USERVER_H

#include <QtWidgets>
#include "chatpage.h"
#include "globalvalue.h"

namespace Ui {
class UServer;
}

class UServer : public QWidget
{
    Q_OBJECT

public:
    explicit UServer(QWidget *parent = 0);
    ~UServer();

private slots:
    void on_pushButton_clicked();

private:
    Ui::UServer *ui;
    ChatPage *chatting;
};

#endif // USERVER_H
userver.cpp
#include "userver.h"
#include "ui_userver.h"

UServer::UServer(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::UServer)
{
    ui->setupUi(this);
    this->setWindowTitle("登录");
}

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

void UServer::on_pushButton_clicked()
{
    GlobalValue::ipaddr = ui->ipEdit->text();
    GlobalValue::port = ui->portEdit->text().toUShort();

    chatting = new ChatPage;

    chatting->show();   // 初始化一个新的界面,然后进行跳转
    this->close();
}

运行效果如下:
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

Python~字典快速上手

目录 Key的重要性 一 创建字典{} 二 字典用key查找 in(遍历)和[]用key查找 keyerror in和[]的效率对比 三 字典的插入/修改/删除(先查找) ​编辑 四 字典增删查改/遍历的效率 五 字典的遍历 for遍历可迭代对象拿到key 与创建顺序相同 keys/values/items方法 六 可…

基于Java+SpringBoot+MyBatis-plus+Vue前后端分离小区管理系统设计与实现2.0

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

抖店一件代发实操,干货满满!

我是电商珠珠 没有货源的新手&#xff0c;在店铺刚开始的时候可以搞无货源模式&#xff0c;也就是一件代发&#xff0c;去搬运别人店铺的商品到自己店铺&#xff0c;再去利用信息差去赚取差价。 很多人不知道具体要怎么做&#xff0c;今天我就来给大家讲一讲。 一、入驻 入…

NNDL 作业12-优化算法2D可视化 [HBU]

老师作业原博客地址&#xff1a;【23-24 秋学期】NNDL 作业12 优化算法2D可视化-CSDN博客 目录 简要介绍图中的优化算法&#xff0c;编程实现并2D可视化 1. 被优化函数 ​编辑 深度学习中的优化算法总结 - ZingpLiu - 博客园 (cnblogs.com) SGD: Adagrad: RMSprop: Mom…

Unity新动画系统之动画层和动画遮罩

Unity新动画系统之动画层和动画遮罩 一、介绍二、动画骨骼遮罩层使用第一种就是create一个avatar Mask,如下&#xff1a;第二种遮罩&#xff0c;就是直接在动画剪辑的属性上更改&#xff0c;如图一为humanoid类型的动画剪辑属性&#xff1a; 一、介绍 之前分享过FSM动画控制系…

消息队列之关于如何实现延时队列

一、延时队列的应用 1.1 什么是延时队列&#xff1f; 顾名思义&#xff1a;首先它要具有队列的特性&#xff0c;再给它附加一个延迟消费队列消息的功能&#xff0c;也就是说可以指定队列中的消息在哪个时间点被消费。 延时队列在项目中的应用还是比较多的&#xff0c;尤其像…

orangepi5plus刷自编译armbian系统

准备好一个编译主机&#xff0c;配置尽量高一点。尽可能有上google的环境配置。 主要步骤 1. 克隆源码 armbian源码仓库 2. 配置apt源 更改/etc/apt/sources.list为国内源&#xff0c;比如我这里ubuntu主机配置清华源。 然后执行apt-get -y update && apt-get -y…

【docker笔记】docker理论及安装

前言 本笔记来源于尚硅谷docker教学视频 视频地址&#xff1a;https://www.bilibili.com/video/BV1gr4y1U7CY/?spm_id_from333.337.search-card.all.click 纯手打笔记&#xff0c;来之不易&#xff0c;感谢支持~ Docker简介 docker为什么会出现 想象一下&#xff1a;一个应用…

若依vue如何展示一个HTML页面(或者展示Markdown文档)

一. 前言 ⚠ 本文是展示Markdown的方法,不能直接前端编辑Markdown文档. 二. 准备部分 用Typora编辑器打开需要导出html页面,我这里使用Typora来导出 1. 先将md文件导出成html 2. 将导出好的文件放在若依vue的pubilc下(文件可以是中文) 三. 代码部分 1.使用v-html来展示HT…

【算法】利用双指针解决算法题(C++)

文章目录 1. 前言2. 双指针法引入283.移动零 3. 使用双指针法解决算法题1089.复写零202.快乐数11.盛最多水的容器[611.有效三角 形的个数](https://leetcode.cn/problems/valid-triangle-number/description/)LCR179.查找总价格为目标值的两个商品15.三数之和 1. 前言 双指针并…

AcWing 889. 满足条件的01序列(卡特兰数应用)

满足条件的01序列 假设长度为n个序列要求满足题意1的前缀0的个数不能超过1的个数 将问题抽象为从(0, 0)到(n, n) 向上走一个代表这一步对应序列中的值是1&#xff0c;向右走代表序列中的值是0 要想满足1的前缀0的数量大于1的数量就需要满足所有路过的途径在y x这个函数个下面…

java进阶学习笔记

学习java深度学习&#xff0c;提升编程思维&#xff0c;适合掌握基础知识的工作者学习 1.反射和代理1.1 概念介绍1.2应用场景1.3 反射-reflect1.3.1 获得类-Class1.3.2 获得类的字段-Field1.3.3 动态访问和修改对象实例的字段1.3.4 获得类方法-Method1.3.5 调用方法.invoke1.3.…

SpringBoot多模块项目下的包和组件扫描

问题阐述&#xff1a;为了简化项目代码&#xff0c;我们通常会使用多模块化代码进行开发&#xff0c;但是会出现如下问题&#xff1a;写代码时能够正常扫描或注入其他模块的Service&#xff0c;但是启动类一启动就报错Consider defining a bean of type com.xiaoqian.common.se…

【MATLAB第85期】基于MATLAB的2023年智能进化算法/元启发式算法合集(持续更新)

【MATLAB第85期】基于MATLAB的2023年智能进化算法/元启发式算法合集&#xff08;持续更新&#xff09; 1.海象进化算法&#xff08;Walrus Optimization Algorithm&#xff09; 作者&#xff1a;Pavel Trojovsk and Mohammad Dehghani 2.暴龙优化算法&#xff08;Tyrannosa…

java设计模式学习之【责任链模式】

文章目录 引言责任链模式简介定义与用途实现方式 使用场景优势与劣势在Spring框架中的应用日志示例代码地址 引言 在现实生活中&#xff0c;常常会遇到这样的场景&#xff1a;一个请求或命令需要经过多个层级的处理。例如&#xff0c;一个行政审批流程可能需要通过多个部门的审…

H5 cryptojs加密算法

1. cryptojs是什么&#xff1f; 有时候项目涉及到的敏感数据比较多&#xff0c;为了信息安全&#xff0c;我们常常需要对一些数据进行接口加密处理&#xff0c;如编码、将明文转化为暗文、加密比对、AES BASE64 算法加密等。 接下来我们就分别说一下 CryptoJS 常用的一些方法。…

爬虫是什么?起什么作用?

【爬虫】 如果把互联网比作一张大的蜘蛛网&#xff0c;数据便是放于蜘蛛网的各个节点&#xff0c;而爬虫就是一只小蜘蛛&#xff0c;沿着网络抓取自己得猎物&#xff08;数据&#xff09;。这种解释可能更容易理解&#xff0c;官网的&#xff0c;就是下面这个。 爬虫是一种自动…

jvm对象探究

hostpot虚拟机对象探究 jvm虚拟机创建对象的流程 ava虚拟机&#xff08;JVM&#xff09;创建对象的过程包括以下步骤&#xff1a; 类加载&#xff1a; 首先&#xff0c;JVM会检查对象的类是否已经被加载。如果该类还没有被加载&#xff0c;JVM会通过类加载器加载该类的字节码…

TCP服务器的演变过程:多进程实现一对多的TCP服务器

使用多进程实现一对多的TCP服务器 一、前言二、新增使用的fork()函数三、实现步骤四、完整代码五、TCP客户端5.1、自己实现一个TCP客户端5.2、Windows下可以使用NetAssist的网络助手工具 小结 一、前言 手把手教你从0开始编写TCP服务器程序&#xff0c;体验开局一块砖&#xf…

【C++】unordered_set/unordered_multiset/unordered_map/unordered_multimap

我们下面来学习C的另外两个容器&#xff1a;unordered_set和unordered_map 目录 一、unordered系列关联式容器 二、unordered_map 2.1 unordered_map的介绍 2.2 unordered_map的接口说明 2.2.1 unordered_map的构造 2.2.2 unordered_map的容量 2.2.3 unordered_map的迭…