Qt网络编程2-基于UDP编程

Qt网络编程2-基于UDP编程

1 UDP概述:

用户数据报协议(User data Protocol)是一种简单轻量级,不可靠,面向数据,无连接的传输层协议.可用在可靠性不是十分重要的场合.如短消息 广播信息等
适合应用的情况有一下几种:

  • 网络数据大多为短消息
  • 拥有大量的客户端
  • 对数据安全性无特殊要求
  • 网络负担非常重,但对响应速度要求高.

2 UDP工作原理
在这里插入图片描述

UDP客户端向UDP服务器发送一定长度的请求报文,报文大小限制和各系统的协议实现有关,但不能超过其下层规定的64kB,UDP服务器同样以报文的形式做出响应.但如果服务器为收到请求,UDP客户端是不会进行重发的.因此报文的传输不可靠.

3 UDP的编程模型
3.1 客户端的编程模型

1 初始化套接字
2 向服务器发送数据
3 接收服务器发送的数据
4 关闭套接字

3.2 服务器的编程模型
1 .初始化套接字
2 绑定ip地址.端口号
3 接收数据,阻塞等待直到收到客户数据
4 处理请求,发送数据

4 Qt中的UDP编程

Qt中的UDP编程是通过QUdpSocket实现的.使用这个类的方法是先绑定Ip地址和端口号,使用bind函数,然后调用writeDatagram()和readDatagram/receiveDatagram完成数据的传输.

4.1 相关成员函数介绍

1)bind()

//绑定ip地址和端口号
bool QAbstractSocket::bind(const QHostAddress &address, quint16 port = 0)

2)writeDatagram()

//向指定ip地址和端口号的主机中发送数据
qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port)

发送的数据超过512个字节.通常是被阻止的,即使成功发送,也会被ip层分裂.
3 )readDatagram
如果maxSize的值太小,数据报中剩余的部分会被丢弃.为了避免这种情况,可以调用pendingDatagramSize()返回数据包中第一个待接收的数据报的大小.

qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address = nullptr, quint16 *port = nullptr)

4 )hasPendingDatagrams()
判断是否有等待读取的数据报
如果至少有一个数据报等待被读取,返回true.

bool QUdpSocket::hasPendingDatagrams() const

5 )pendingDatagramSize()
返回第一个未读取数据报的大小,如果没有数据报 函数返回-1

qint64 QUdpSocket::pendingDatagramSize() const

5 UDP广播程序

接收端源码:

#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget),isStarted(false),port(8888)
{
    ui->setupUi(this);
    udpSocket = new QUdpSocket(this);
}
Widget::~Widget()
{
    delete ui;
}
void Widget::on_startBtn_clicked()
{
    if(!isStarted){
        isStarted = true;
        ui->startBtn->setText("停止接收");
        ui->rcvlineEdit->setEnabled(false);
        port = ui->rcvlineEdit->text().toShort();
        if(udpSocket->bind(port) == false)
            qDebug() << "绑定端口号失败";
        connect(udpSocket,&QUdpSocket::readyRead,this,&Widget::receiveMessage);
    }
    else{
         isStarted = false;
         ui->startBtn->setText("开始接收");
         ui->rcvlineEdit->setEnabled(true);
         udpSocket->close();
    }
}
void Widget::receiveMessage(void){
    //判断是否有等待读取的数据报
    if(udpSocket->hasPendingDatagrams()){
        QByteArray buf;
        //获取数据包的大小
        buf.resize(udpSocket->pendingDatagramSize());
        //读取数据包 data 数据转换为char*
        udpSocket->readDatagram(buf.data(),buf.size());
        //qDebug() << buf.data();
        ui->listWidget->addItem(buf);
        //滚动到最底部
        ui->listWidget->scrollToBottom();
    }
}

发送端源码

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget),isStarted(false)
{
    setWindowTitle("广播接收端");
    udpSocket = new QUdpSocket(this);
    timer  = new QTimer(this);
    ui->setupUi(this);
    //定时器到时发送timeout信号
    connect(timer,&QTimer::timeout,this,&Widget::sendMessage);
}

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

//开始广播
void Widget::on_startBtn_clicked()
{
    if(!isStarted){
        isStarted = true;
        ui->startBtn->setText("停止广播");
        ui->msgLineEdit->setEnabled(false);
        ui->portLineEdit->setEnabled(false);
        //开始定时器 ,每个1秒广播一次
        timer->start(1000);
    }
    else{
        isStarted=false;
        ui->startBtn->setText("开始广播");
        ui->msgLineEdit->setEnabled(true);
        ui->portLineEdit->setEnabled(true);
        timer->stop();
    }
}
void Widget::sendMessage(void){
    quint16 port = ui->portLineEdit->text().toShort();
    QString msg = ui->msgLineEdit->text();
    //发送消息 toUtf8转换为QByteArray 字符数组 不要把msg.lenth()加进去 否则会导致部分数据接收不完整
    qint64 len =  udpSocket->writeDatagram(msg.toUtf8(),QHostAddress::Broadcast,port);
}

6 运行结果

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值