【Qt】Qt 网络 | UDP Socket

文章目录

要使用 Qt 网络编程,需要在项目中的 .pro 文件中添加 network 模块

核心API

Qt 的 UDP Socket 主要的类有两个 QUdpSocketQNetworkDatagram

因为是 UDP 是面向数据报的,QNetworkDatagram 就是对 数据报的封装,内容包括:对端发送的数据,对端的 IP 和 端口号

QUdpSocket 表示一个 UDP 的 socket 文件

名称 类型 说明 对标原生API
bind(const QHostAddress &address, quint16 port = 0) 方法 绑定指定的 IP地址 和 端口号 bind
receiveDatagram() 方法 返回 QNetworkDatagram 读取一个 UDP 数据报 recvfrom
writeDatagram(const QNetworkDatagram &datagram) 方法 发送一个 UDP 数据报 sendto
writeDatagram(const char *data, qint64 size, const HostAddress &address, quint16 port) 方法 data是要发送的数据,size是数据的长度,address是目标 IP地址,port是目标端口号 sendto
readyRead 信号 在收到数据并准备就绪后触发 类似于 IO 多路复用的通知机制

QNetworkDatagram 表示一个 UDP 数据报

名称 类型 说明 对标原生API
QNetworkDatagram(const QByteArray &data, const QHostAddress &destinationAddress = QHostAddress(), quint16 port = 0) 构造函数 通过 QByteArray,目标 IP地址,目标端口号构造一个 UDP 数据报,通常用于发送数据
data() 方法 获取数据报内部持有的数据,返回 QByteArray
senderAddress() 方法 获取数据报中包含的对端的IP地址 recvfrom 包含了该功能
senderPort() 方法 获取数据报中包含的对端的端口号 recvfrom 包含了该功能

代码示例

通过模拟 客户服务器的UDP通信 熟悉上述方法使用

客户端通过输入栏获取数据,点击按钮发送给服务端

服务端接受客户端数据,并返回相同数据,验证通信无误

服务器

  1. 创建界面,包含一个 QListWidget 用来显示消息
  2. 创建 QUdpSocket 成员,修改 widget.h
cpp 复制代码
class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
//槽函数
public slots:
    void handleRequest();//处理客户端请求
private:
    QString process(const QString &request);//业务处理逻辑
private:
    Ui::Widget *ui;
    QUdpSocket *socket;//套接字
};
  1. 编写 widget.cpp,实现相关方法

因为 UDP 是无连接的,绑定端口号后就可以接受数据了,所以要先对 readReady信号连接槽函数

逻辑如下:1. 设置窗口标题 2. 创建套接字 3. 连接信号槽 4. 绑定端口号

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //1. 设置窗口标题
    this->setWindowTitle("服务端");
    //2. 创建套接字
    socket = new QUdpSocket(this);
    //UDP绑定完就开启服务了,所以需要先连接信号槽
    //3. 连接信号槽
    connect(socket, &QUdpSocket::readyRead, this, &Widget::handleRequest);
    //4. 绑定,服务端绑定任意IP,端口号指定为9090
    bool ret = socket->bind(QHostAddress::Any, 9090);
    if(!ret)
    {
        QMessageBox::critical(this, "错误", "绑定套接字失败");
        return;
    }

}

编写 readReady 对应槽函数

逻辑如下:1. 获取用户数据报 2. 提取其中数据 3. 业务处理 4. 返回响应

cpp 复制代码
void Widget::handleRequest()
{
    //1. 获取用户数据报
    const QNetworkDatagram requestDatagram = socket->receiveDatagram();
    //2. 提取其中数据
    QString request = requestDatagram.data();
    //3. 业务处理逻辑
    QString responce = process(request);
    //4. 记录客户端数据
    QString log = "[" + requestDatagram.senderAddress().toString() + ":" + QString::number(requestDatagram.senderPort())
                + "]  request:" + request + "  responce:" + responce;
    ui->listWidget->addItem(log);
    //5. 返回响应
    QNetworkDatagram responceDatagram(responce.toUtf8(), requestDatagram.senderAddress(), requestDatagram.senderPort());
    socket->writeDatagram(responceDatagram);
}

此处服务器的业务处理只是简单的回显数据

cpp 复制代码
QString Widget::process(const QString &request)
{
    return request;
}

客户端

  1. 创建界面。包含 一个 QLineEditQPushButtonQListWidget
    通过布局管理器搭配,规范界面
  2. 声明全局常量:服务端的 IP地址端口号
cpp 复制代码
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 9090
  1. 创建 QUdpSocket 成员,修改 widget.h,定义成员
cpp 复制代码
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private slots:
    //按钮点击槽函数
    void on_pushButton_clicked();
    //客户端业务处理逻辑
    void handleRequest();
private:
    Ui::Widget *ui;
    QUdpSocket *socket;
};
  1. 修改 widget.cpp,初始化 socket
    客户端不需要绑定端口号
cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->pushButton->setShortcut(QKeySequence(Qt::Key_Return));
    //设置窗口标题
    this->setWindowTitle("客户端");
    //创建套接字
    socket = new QUdpSocket(this);
    //连接信号槽
    connect(socket, &QUdpSocket::readyRead, this, &Widget::handleRequest);
}

按钮点击槽函数

逻辑如下:1. 获取输入栏文本 2. 记录发送信息 3. 将消息发送给服务端 4. 清空输入栏

cpp 复制代码
void Widget::on_pushButton_clicked()
{
    //1. 获取输入栏的文本
    QString text = ui->lineEdit->text();
    QNetworkDatagram requestDatagram(text.toUtf8(), QHostAddress(SERVER_IP), SERVER_PORT);
    //2. 记录发送信息
    QString message = "发送:" + text;
    ui->listWidget->addItem(message);
    //3. 将消息发送给服务端
    socket->writeDatagram(requestDatagram);
    //4. 将输入栏清空
    ui->lineEdit->clear();
}

客户端业务处理函数

cpp 复制代码
void Widget::handleRequest()
{
    //1. 获取服务端返回的数据报
    QNetworkDatagram responceDatagram = socket->receiveDatagram();
    QString responce = responceDatagram.data();
    //2. 显示消息
    ui->listWidget->addItem("接收:" + responce);
}

运行结果如下:

结束语

感谢你的阅读

如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。

相关推荐
喜欢吃燃面4 小时前
Linux:环境变量
linux·开发语言·学习
qq_192779875 小时前
C++模块化编程指南
开发语言·c++·算法
代码村新手5 小时前
C++-String
开发语言·c++
qq_401700415 小时前
Qt 中文乱码的根源:QString::fromLocal8Bit 和 fromUtf8 区别在哪?
开发语言·qt
Cisco_hw_zte7 小时前
小型网络中部署Aruba无线
网络
历程里程碑7 小时前
滑动窗口---- 无重复字符的最长子串
java·数据结构·c++·python·算法·leetcode·django
佑白雪乐7 小时前
<Linux基础第10集>复习前面内容
linux·运维·服务器
春日见7 小时前
自动驾驶规划控制决策知识点扫盲
linux·运维·服务器·人工智能·机器学习·自动驾驶
暮云星影7 小时前
四、linux系统 应用开发:UI开发环境配置概述 (三)
linux·ui·arm
2501_940315268 小时前
航电oj:首字母变大写
开发语言·c++·算法