【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
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. 绑定端口号

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. 返回响应

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

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

QString Widget::process(const QString &request)
{
    return request;
}

客户端

  1. 创建界面。包含 一个 QLineEditQPushButtonQListWidget
    通过布局管理器搭配,规范界面
    在这里插入图片描述
  2. 声明全局常量:服务端的 IP地址端口号
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 9090
  1. 创建 QUdpSocket 成员,修改 widget.h,定义成员
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
    客户端不需要绑定端口号
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. 清空输入栏

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

客户端业务处理函数

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

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

结束语
感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

  • 24
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值