Qt 网络编程

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();
}

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

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

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

相关文章

【微服务】springboot整合kafka-stream使用详解

目录 一、前言 二、kafka stream概述 2.1 什么是kafka stream 2.2 为什么需要kafka stream 2.2.1 对接成本低 2.2.2 节省资源 2.2.3 使用简单 2.3 kafka stream特点 2.4 kafka stream中的一些概念 2.5 Kafka Stream应用场景 三、环境准备 3.1 搭建zk 3.1.1 自定义d…

05|提示工程(下):用思维链和思维树提升模型思考质量 ## 什么是 Chain of Thought

05&#xff5c;提示工程&#xff08;下&#xff09;&#xff1a;用思维链和思维树提升模型思考质量 什么是 Chain of Thought CoT 这个概念来源于学术界&#xff0c;是谷歌大脑的 Jason Wei 等人于 2022 年在论文《Chain-of-Thought Prompting Elicits Reasoning in Large La…

Unity使用Rider作为默认编辑器

01.Edit -> Preferences 02.Externel Tools -> Open by file extension 如果界面选项有Rider直接选择&#xff0c;如果没有选择Browse) 03.选择rider64.exe 04.成功关联

【C# 技术】 C# 常用排序方式——常规数据排序

C# 常用排序方式——常规数据排序 前言 在最近的项目中经常会对C#中的数据进行排序&#xff0c;对于基本数据类型&#xff0c;其排序方式比较简单&#xff0c;只需要调用内置算法即可实现&#xff0c;但对于自定义数据类型以及自定义排序规则的情况实现起来就比较麻烦&#…

西门子博途与菲尼克斯无线蓝牙模块通讯

菲尼克斯无线蓝牙模块 正常运行时,可以使用基站控制字0发送00E0(得到错误代码命令) 正常运行时,可以使用基站控制字0发送00E0(得到错误代码命令)得到各个无线I/O是否连 接的信号(状态字IN word 1的第2、6、10位) 小车1连接状态 小车2连接状态 小车3连接状态 1#小车自…

操作系统 day18(死锁)

死锁 定义 在并发环境下&#xff0c;各进程因竞争资源而造成的一种互相等待对方手里的资源 &#xff0c;导致各进程都阻塞&#xff0c;都无法向前推进的现象&#xff0c;就是死锁。发生死锁后若无外力干涉&#xff0c;这些进程都将无法向前推进。如下图&#xff1a; 死锁、饥饿…

激发大规模ClickHouse数据加载(2/3)大规模数据加载的加速调优

本文字数&#xff1a;4552&#xff1b;估计阅读时间&#xff1a;12 分钟 作者&#xff1a;Maksim Kita 审校&#xff1a;庄晓东&#xff08;魏庄&#xff09; 本文在公众号【ClickHouseInc】首发 Meetup活动&#xff1a; ClickHouse Shenzhen User Group第1届 Meetup 火热报名中…

网络第3天

基于UDP的TFTP文件传输 功能&#xff1a;下载、上传、退出 #include <myhead.h> #define IP "192.168.8.100" #define PORT 69 int download_file(int…

方法论系列:数据科学框架入门

目录 第一章 - 数据科学家如何战胜困难第二章 - 数据科学框架第三章 - 步骤1&#xff1a;定义问题和步骤2&#xff1a;收集数据第四章 - 步骤3&#xff1a;准备数据第五章 - 数据清洗的4个C&#xff1a;纠正、补全、创建和转换第六章 - 步骤4&#xff1a;使用统计学进行探索性…

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

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

组学无参比对教程

转录组无参比对教程 当作物是没有参考基因组时&#xff0c;需要无参进行比对。Trinity是现在使用最广泛的转录组De novo组装软件。 Trinity 是无参考转录组从头组装转录组的常用软件&#xff0c;且trinity的使用文档非常详细&#xff0c;整合的内容非常完整&#xff0c;包括从…

企业知识库在跨地域团队协作中的价值

随着全球化进程的不断加速&#xff0c;越来越多的企业开始面临跨地域协作的挑战。在这种背景下&#xff0c;企业知识库作为一种重要的知识管理工具&#xff0c;对于提高团队协作效率、促进知识共享与创新具有不可替代的价值。接下来就说一下知识库在跨地域团队协作中的重要性及…

OpenSSH升级指南:实战检验的步骤,有效加固服务器安全

在做服务器漏扫时我们经常会遇到有关于OpenSSH相关的安全漏洞&#xff0c;本文主要给大家介绍一下有关于OpenSSH的升级方法&#xff0c;小伙伴们可以参考一下流程&#xff0c;按步骤操作&#xff0c;但是过程中一定会遇到各种各样的问题&#xff0c;需要自行解决&#xff0c;这…

怎么为pdf文件添加水印?

怎么为pdf文件添加水印&#xff1f;PDF是一种很好用的文件格式&#xff0c;这种格式能够很有效的保护我们的文件&#xff0c;但有时可能还会被破解&#xff0c;这种时候在PDF上添加水印就是比较好的方法。 综上所述&#xff0c;PDF是保密性很强的文件&#xff0c;但添加水印能够…

二维码初体验 com.google.zxing 实现续 - web api封装

文章目录 一、概述二、最终效果三、源码结构四、完整代码 一、概述 在 二维码初体验 com.google.zxing 实现 我们实现了二维码的生成&#xff0c;但是大部分情况下&#xff0c;二维码的相关功能是作为API接口来提供服务的。 我们下面便演示在springboot、Knife4j下封装api接口…

【小沐学Python】Python实现Web服务器(aiohttp)

文章目录 1、简介2、下载和安装3、代码测试3.1 客户端3.2 服务端 4、更多测试4.1 asyncio4.2 aiohttpHTTP服务器4.3 aiohttp爬虫实例4.4 aiohttprequests比较 结语 1、简介 https://github.com/aio-libs/aiohttp https://docs.aiohttp.org/en/stable/index.html Asynchronous …

C/C++图型化编程

一、创建图形化窗口&#xff1a; 1.包含头文件&#xff1a; graphics.h:包含已经被淘汰的函数easyx.h:只包含最新的函数 2.两个函数就可以创建窗口&#xff1a; 打开&#xff1a;initgraph(int x,int y,int style);关闭&#xff1a;closegraph(); 3.窗口坐标的设置&#…

【眼镜】相关知识

眼镜相关 配眼镜可以事先了解的事情&#xff1a; 折射率&#xff1a;先说结论&#xff0c;高度数可以考虑选高折射率&#xff0c;低度数没必要。 折射率&#xff1a;1.50折射率 1.56折射率 1.60折射率 1.67折射率 1.71折射率 1.74折射率. 折射率越高&#xff0c;镜片越薄&a…

全面理解Stable Diffusion采样器

全面理解Stable Diffusion采样器 原文&#xff1a;Stable Diffusion Samplers: A Comprehensive Guide 在 AUTOMATIC1111 的 SD webui 中&#xff0c;有许多采样器&#xff08;sampler&#xff09;&#xff0c;如 Euler a&#xff0c;Heun&#xff0c;DDIM&#xff0c;… 什么是…

应急响应中的溯源方法

在发现有入侵者后&#xff0c;快速由守转攻&#xff0c;进行精准地溯源反制&#xff0c;收集攻击路径和攻击者身份信息&#xff0c;勾勒出完整的攻击者画像。 对内溯源与对内溯源 对内溯源&#xff1a;确认攻击者的行为 &#xff0c;分析日志 数据包等&#xff1b; 对外溯源&…