当前位置:   article > 正文

Qt之UDP通信_qt udp

qt udp

目录

一、UDP简介

二、QUdpSocket类

三、UDP服务器

四、UDP客户端

五、代码

1.udp服务端

2.udp客户端


一、UDP简介

UDP(User Datagram Protocol 即用户数据报协议)是一个轻量级的,不可靠的,面向数据
报的无连接协议
。由于 UDP 的特性:它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用 UDP 较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。

UDP 通信示意图如下:

UDP 消息传送有三种模式,分别是单播广播组播三种模式。

①单播(unicast): 单播用于两个主机之间的端对端通信,需要知道对方的 IP 地址与端口

②广播(broadcast): 广播 UDP 与单播 UDP 的区别就是 IP 地址不同,广播一般使用广播地址
255.255.255.255,将消息发送到在同一广播(也就是局域网内同一网段) 网络上的每个主机

注意:本地广播信息是不会被路由器转发所以如果一个服务端在win,另外一个客户端在虚拟机说,这时就需要配置虚拟机的端口转发,这样虚拟机才会连得上服务器



③组播(multicast): 组播(多点广播),也称为多播,将网络中同一业务类型主机进行了逻辑上的分组,进行数据收发的时候其数据仅仅在同一分组中进行,其他的主机没有加入此分组不能收发对应的数据。

广域网上广播的时候,其中的交换机和路由器只向需要获取数据的主机复制并转发数据。主机可以向路由器请求加入或退出某个组,网络中的路由器和交换机有选择地复制并传输数据,将数据仅仅传输给组内的主机。多播的这种功能,可以一次将数据发送到多个主机,又能保证不影响其他不需要(未加入组)的主机的其他通信。

注意: 单播一样和多播是允许在广域网即 Internet 上进行传输的,而广播仅仅在同一局域网上才能进行


二、QUdpSocket类

QT 的 socket 类之间的关系: 

QUdpSocket 类提供了一个 UDP 套接字。 QUdpSocket 是 QAbstractSocket 的子类,允许发
送和接收 UDP 数据报。

常用API函数

①构造函数

QUdpSocket::QUdpSocket(QObject *parent = Q_NULLPTR)

②如果至少有一个数据报在等待被读取,则返回true,否则返回false。

bool QUdpSocket::hasPendingDatagrams() const 

③服务器绑定端口

bool bind(const QHostAddress &address, quint16 port = 0, BindMode mode = DefaultForPlatform);

④返回第一个待处理的UDP数据报的大小Byte。如果没有可用的数据报,该函数返回-1。

qint64 QUdpSocket::pendingDatagramSize() const

⑤接收数据

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

接收一个不大于maxSize字节的数据报并将其存储在data中。发送者的主机地址和端口存储在*address和*port中(除非指针为0)。成功时返回数据报的大小;否则返回-1。

如果maxSize太小,数据报的其余部分将被丢失。为了避免数据丢失,在试图读取数据报之前,应调用pendingDatagramSize()来确定未决数据报的大小。如果maxSize为0,数据报将被丢弃。
 

⑥发送数据

qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port)

将数据报以大小的方式发送到端口端口的主机地址。成功时返回发送的字节数,否则返回-1。
数据报总是被写成一个块。数据报的最大尺寸与平台高度相关,但可以低至8192字节。如果数据报太大,这个函数将返回-1,error()将返回DatagramTooLargeError。

一般来说,发送大于512字节的数据报是不利的,因为即使它们被成功发送,在到达最终目的地之前,它们很可能被IP层分割开来。

 三、UDP服务器

 1.创建QUdpSocket对象

mSocket = new QUdpSocket(this);

②绑定地址和端口号

msocket->bind(ip,端口号);

③收到数据时,会触发readyRead()信号,自定义readPendingDatagrams()进行读取数据;

connect(msocket,&QUdpSocket::readyRead, this,&Widget::readPendingDatagrams);

④在while循环中读取数据,只要有数据,就一直读取并处理。

  void Server::readPendingDatagrams()
  {
      while (udpSocket->hasPendingDatagrams()) //数据报等待被读取

       {
                 //数据缓冲区

                QByteArray arr;

                //调整缓冲区的大小和收到的数据大小一致                 

                arr.resize(mSocket->bytesAvailable()); //接收数据

                mSocket->readDatagram(arr.data(),arr.size(),&addr,&port);

                //将arr.data转为字符串即可

                QString str = arr.data();

      }
  }

通信(先接收) 收到数据会触发信号readyRead, 通过QUdpSocket对象的readDatagram函数来接收数据 。

readyRead()信号在数据报到达时发出。在这种情况下, hasPendingDatagrams()返回 true。调用 pendingDatagramSize()来获取第一个待处理数据报的大小,并调用 readDatagram()接收数据。

注意:当接收到readyRead()信号时,一个传入的数据报应该被读取,否则这个信号将不会被发送到下一个数据报。

⑤发送数据

qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port)

若是广播消息,与单播消息不同的是将目标 IP 地址换成了广播地址,一般广播地址为 255.255.255.255,也可以使用QHostAddress::Broadcast获取广播地址

QHostAddress peerAddr = QHostAddress::Broadcast;

只需要将客户端发送数据:writeDatagramIP地址改为广播地址即可

四、UDP客户端

①创建QUdpSocket对象

mSocket = new QUdpSocket(this);

②发送数据到指定的地址和端口号

writeDatagram(数据,接收方ip,接收方端口号);

 发送的数据要是QByteArray类型,Qt中将字符串转为QByteArray可以使用.toUtf8函数

五、代码

1.udp服务端

 头文件

  1. #ifndef UDPSERVER_H
  2. #define UDPSERVER_H
  3. #include <QWidget>
  4. #include <QtNetwork>
  5. QT_BEGIN_NAMESPACE
  6. namespace Ui { class UdpServer; }
  7. QT_END_NAMESPACE
  8. class UdpServer : public QWidget
  9. {
  10. Q_OBJECT
  11. public:
  12. UdpServer(QWidget *parent = nullptr);
  13. ~UdpServer();
  14. private slots:
  15. void on_pushButton_start_clicked();
  16. void on_pushButton_send_clicked();
  17. void readPendingDatagrams();
  18. private:
  19. Ui::UdpServer *ui;
  20. //Udp服务器
  21. QUdpSocket *mSocket;
  22. //通信的ip和端口,用于获取发送者的 IP 和端口
  23. QHostAddress addr;
  24. quint16 port;
  25. };
  26. #endif // UDPSERVER_H

源文件

  1. #include "udpserver.h"
  2. #include "ui_udpserver.h"
  3. UdpServer::UdpServer(QWidget *parent)
  4. : QWidget(parent)
  5. , ui(new Ui::UdpServer)
  6. {
  7. ui->setupUi(this);
  8. }
  9. UdpServer::~UdpServer()
  10. {
  11. delete ui;
  12. }
  13. //启动
  14. void UdpServer::on_pushButton_start_clicked()
  15. {
  16. //1.创建QUdpSocket对象
  17. mSocket = new QUdpSocket(this);
  18. //2.连接接收数据信号和槽
  19. QObject::connect(mSocket,&QUdpSocket::readyRead,this,&UdpServer::readPendingDatagrams);
  20. //3.绑定
  21. mSocket->bind(QHostAddress::Any,ui->spinBox->value());
  22. //连接回车发送的信号和槽
  23. QObject::connect(ui->lineEdit,&QLineEdit::returnPressed,this,&UdpServer::on_pushButton_send_clicked);
  24. //禁止端口号和启动按钮
  25. ui->spinBox->setEnabled(false);
  26. ui->pushButton_start->setEnabled(false);
  27. }
  28. void UdpServer::on_pushButton_send_clicked()
  29. {
  30. //获取发送的数据
  31. QByteArray arr = ui->lineEdit->text().toUtf8();
  32. //发送
  33. mSocket->writeDatagram(arr,addr,port);
  34. //显示发送的内容
  35. ui->textBrowser->insertPlainText("send:"+QString(arr)+"\n");
  36. //情况lineEdit
  37. ui->lineEdit->clear();
  38. }
  39. void UdpServer::readPendingDatagrams()
  40. {
  41. //数据缓冲区
  42. QByteArray arr;
  43. while(mSocket->hasPendingDatagrams())
  44. {
  45. //调整缓冲区的大小和收到的数据大小一致
  46. arr.resize(mSocket->bytesAvailable());
  47. //接收数据
  48. mSocket->readDatagram(arr.data(),arr.size(),&addr,&port);
  49. //显示
  50. ui->textBrowser->insertPlainText(addr.toString()+":"+QString(arr)+"\n");
  51. //使能发送按钮和编辑框
  52. ui->lineEdit->setEnabled(true);
  53. ui->pushButton_send->setEnabled(true);
  54. }
  55. }

2.udp客户端

头文件

  1. #ifndef UDPCILENT_H
  2. #define UDPCILENT_H
  3. #include <QWidget>
  4. #include <QtNetwork>
  5. QT_BEGIN_NAMESPACE
  6. namespace Ui { class UdpCilent; }
  7. QT_END_NAMESPACE
  8. class UdpCilent : public QWidget
  9. {
  10. Q_OBJECT
  11. public:
  12. UdpCilent(QWidget *parent = nullptr);
  13. ~UdpCilent();
  14. private slots:
  15. void on_pushButton_send_clicked();
  16. void readPendingDatagrams();
  17. private:
  18. Ui::UdpCilent *ui;
  19. //UDP客户端
  20. QUdpSocket *mSocket;
  21. };
  22. #endif // UDPCILENT_H

 源文件

  1. #include "udpcilent.h"
  2. #include "ui_udpcilent.h"
  3. UdpCilent::UdpCilent(QWidget *parent)
  4. : QWidget(parent)
  5. , ui(new Ui::UdpCilent)
  6. {
  7. ui->setupUi(this);
  8. //1.创建QUdpSocket
  9. mSocket = new QUdpSocket(this);
  10. //2.通信(接收)
  11. QObject::connect(mSocket,&QUdpSocket::readyRead,this,&UdpCilent::readPendingDatagrams);
  12. //连接回车发送的信号和槽
  13. QObject::connect(ui->lineEdit_send,&QLineEdit::returnPressed,this,&UdpCilent::on_pushButton_send_clicked);
  14. }
  15. UdpCilent::~UdpCilent()
  16. {
  17. delete ui;
  18. }
  19. //发送
  20. void UdpCilent::on_pushButton_send_clicked()
  21. {
  22. //获取发送的数据
  23. QByteArray arr = ui->lineEdit_send->text().toUtf8();
  24. //发送
  25. //mSocket->writeDatagram(arr,QHostAddress(ui->lineEdit_ip->text()),ui->spinBox->value());
  26. mSocket->writeDatagram(arr,QHostAddress::Broadcast,ui->spinBox->value());
  27. //显示发送的内容
  28. ui->textBrowser->insertPlainText("send:"+QString(arr)+"\n");
  29. //情况lineEdit
  30. ui->lineEdit_send->clear();
  31. }
  32. void UdpCilent::readPendingDatagrams()
  33. {
  34. QHostAddress addr; //用于获取发送者的 IP 和端口
  35. quint16 port;
  36. //数据缓冲区
  37. QByteArray arr;
  38. while(mSocket->hasPendingDatagrams())
  39. {
  40. //调整缓冲区的大小和收到的数据大小一致
  41. arr.resize(mSocket->bytesAvailable());
  42. //接收数据
  43. mSocket->readDatagram(arr.data(),arr.size(),&addr,&port);
  44. //显示
  45. ui->textBrowser->insertPlainText(addr.toString()+":"+QString(arr)+"\n");
  46. }
  47. }

结果: 
 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/627127
推荐阅读
相关标签
  

闽ICP备14008679号