当前位置:   article > 正文

Qt UDP通信聊天程序(单播、广播、组播)_qudpsocket设置广播通信

qudpsocket设置广播通信

1.QUdpSocket

UDP是轻量的、不可靠的、面向数据报、无连接的协议,它可以用于对可靠性要求不高的场合,与TCP通信不同,无需建立持久的socket连接。

QUdpSocket用于实现UDP通信,与QTcpSocket主要区别是,QUdpSocket以数据报传输数据,而不是以连续的数据流。发送数据使用writeDatagram(),数据报的长度一般少于512字节,每个数据报包含发送者和接收者的IP地址和端口等信息。

要进行UDP通信,首先需要bind函数绑定一个端口,用于接收传入的手机不能。当有数据报传入时会发射readyRead()信号,使用readDatagram()来读取接收到的数据报。

UDP消息传送有单播、广播、组播三种模式。

  • 单播:一个UDP客户端发出的数据报只发送到另一个指定地址和端口的UDP客户端,是一对一的数据传输。
  • 广播:一个UDP客户端发出的数据报,在同一网络范围内其他所有的UDP客户端都可以收到。
  • 组播:也称多播,UDP客户端加入到另一个组播IP地址指定的多播组,成员向组播地址发送的数据报组内成员都可以接收到,类似于QQ群功能。

 

在单播、广播和多播下,UDP程序都是对等的,不像TCP那样分为客户端和服务器端。单播和广播的实现方式基本相同,只是数据报的目标IP地址设置不同,多播模式需要加入多播组,实现方式有较大差异。

本文福利,莬费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击莬费领取↓↓ 

2.单播/广播

 

本机运行两个实例需要绑定不同的端口,例如实例A绑定端口2000,实例B绑定端口3000,实例A向实例B发送数据时,需要指定实例B所在主机的IP地址、绑定端口作为目标地址和目标端口,这样实例B才能接收到数据报。如果在不同的计算机运行,则可以使用相同的端口。

  • 要实现数据接收,必须先使用QUdpSocket::bind()绑定一个端口,用于监听传入的数据报。解除绑定则使用abort()函数。
  • writeDatagram()函数向一个目标用户发送消息时,需要指定目标地址和端口。
  • 在广播消息时,只需要将目标地址更换为一个特殊地址,即广播地址QHostAddress::Broadcast,一般为255.255.255.255
  • 发送的数据报是QByteArray类型的字节数组,数据报的长度一般不超过512字节,可以是文本,也可以是二进制数据。
  • 接收到数据报后会发射readyRead()信号。
  1. #ifndef WIDGET_H
  2. #define WIDGET_H
  3. #include <QWidget>
  4. #include <QUdpSocket>
  5. namespace Ui {
  6. class Widget;
  7. }
  8. class Widget : public QWidget
  9. {
  10. Q_OBJECT
  11. public:
  12. explicit Widget(QWidget *parent = 0);
  13. ~Widget();
  14. private slots:
  15. void on_btnBind_clicked();
  16. void on_btnUnBind_clicked();
  17. void on_btnClear_clicked();
  18. void on_btnQuit_clicked();
  19. void on_btnSend_clicked();
  20. void on_btnBroadcast_clicked();
  21. void on_readyRead();
  22. private:
  23. Ui::Widget *ui;
  24. private:
  25. QUdpSocket *m_udpSocket = nullptr;
  26. };
  27. #endif // WIDGET_H
  1. #include "widget.h"
  2. #include "ui_widget.h"
  3. #include <QHostInfo>
  4. Widget::Widget(QWidget *parent) :
  5. QWidget(parent),
  6. ui(new Ui::Widget)
  7. {
  8. ui->setupUi(this);
  9. //本地主机名
  10. QString hostName = QHostInfo::localHostName();
  11. //本机IP地址
  12. QHostInfo hostInfo = QHostInfo::fromName(hostName);
  13. //IP地址列表
  14. QList<QHostAddress> addrList = hostInfo.addresses();
  15. for(int i=0;i<addrList.count();i++)
  16. {
  17. QHostAddress host = addrList.at(i);
  18. if(QAbstractSocket::IPv4Protocol == host.protocol())
  19. {
  20. QString ip = host.toString();
  21. ui->comboBox->addItem(ip);
  22. }
  23. }
  24. m_udpSocket = new QUdpSocket(this);
  25. connect(m_udpSocket,&QUdpSocket::readyRead,this,&Widget::on_readyRead);
  26. }
  27. Widget::~Widget()
  28. {
  29. delete ui;
  30. }
  31. void Widget::on_btnBind_clicked()
  32. {
  33. //本机UDP端口
  34. qint16 port = ui->spinBindPort->value();
  35. if(m_udpSocket->bind(port))
  36. {
  37. ui->plainTextEdit->appendPlainText("**已成功绑定");
  38. ui->plainTextEdit->appendPlainText("**绑定端口: "+QString::number(m_udpSocket->localPort()));
  39. ui->btnBind->setEnabled(false);
  40. ui->btnUnBind->setEnabled(true);
  41. }
  42. else
  43. {
  44. ui->plainTextEdit->appendPlainText("**绑定失败");
  45. }
  46. }
  47. void Widget::on_btnUnBind_clicked()
  48. {
  49. //解除绑定
  50. m_udpSocket->abort();
  51. ui->btnBind->setEnabled(true);
  52. ui->btnUnBind->setEnabled(false);
  53. ui->plainTextEdit->appendPlainText("**已解除绑定");
  54. }
  55. void Widget::on_btnClear_clicked()
  56. {
  57. ui->plainTextEdit->clear();
  58. }
  59. void Widget::on_btnQuit_clicked()
  60. {
  61. }
  62. void Widget::on_btnSend_clicked()//单播
  63. {
  64. //目标IP
  65. QString dstIp = ui->comboBox->currentText();
  66. QHostAddress dstAddr(dstIp);
  67. //目标端口
  68. quint16 dstPort = ui->spinDstPort->value();
  69. QString msg = ui->lineEdit->text();
  70. QByteArray str = msg.toUtf8();
  71. //发出数据报
  72. m_udpSocket->writeDatagram(str,dstAddr,dstPort);
  73. ui->plainTextEdit->appendPlainText("[out] "+msg);
  74. }
  75. void Widget::on_btnBroadcast_clicked()//广播
  76. {
  77. quint16 dstPort = ui->spinDstPort->value();
  78. QString msg = ui->lineEdit->text();
  79. QByteArray str = msg.toUtf8();
  80. //发出数据报
  81. m_udpSocket->writeDatagram(str,QHostAddress::Broadcast,dstPort);
  82. ui->plainTextEdit->appendPlainText("[Broadcast] "+msg);
  83. }
  84. void Widget::on_readyRead()
  85. {
  86. //是否还有待读取的传入数据报
  87. while(m_udpSocket->hasPendingDatagrams())
  88. {
  89. QByteArray data;
  90. //返回待读取的数据报的字节数
  91. data.resize(m_udpSocket->pendingDatagramSize());
  92. QHostAddress peerAddr;
  93. quint16 peerPort;
  94. //读取数据报的内容
  95. m_udpSocket->readDatagram(data.data(),data.size(),&peerAddr,&peerPort);
  96. QString str = data.data();
  97. QString peer = "[From ] +"+peerAddr.toString()+":"+QString::number(peerPort)+"] ";
  98. ui->plainTextEdit->appendPlainText(peer+str);
  99. }
  100. }

3.组播

组播是主机之间“一对一组”的通信模式,当多个客户端加入由一个组播地址定义的多播组之后,客户端向组播地址和端口发送数据报,组内成员都可以接收到,类似QQ群。

UDP组播必须使用一个组播地址。组播地址是D类IP地址,有特定的地址段。多播组可以是永久的也可以是临时的。永久多播组保持不变的是它的IP地址,组内成员结构可以发生变化。

  • 224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其他地址供路由协议使用
  • 224.0.1.0~224.0.1.255是公用组播地址,可以用于internet
  • 224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效
  • 239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效

若在家庭或办公室局域网内测试UDP组播功能,可以使用组播地址范围是239.0.0.0~239.255.255.255

joinMulticastGroup()函数使主机加入一个多播组,leaveMulticastGroup()函数使主机离开一个多播组。

UDP组播的特点是使用组播地址,其他的端口绑定、数据报收发功能与单播UDP完全相同。

 

  1. #ifndef WIDGET_H
  2. #define WIDGET_H
  3. #include <QWidget>
  4. #include <QUdpSocket>
  5. namespace Ui {
  6. class Widget;
  7. }
  8. class Widget : public QWidget
  9. {
  10. Q_OBJECT
  11. public:
  12. explicit Widget(QWidget *parent = 0);
  13. ~Widget();
  14. private slots:
  15. void on_btnClear_clicked();
  16. void on_btnSend_clicked();
  17. void on_readyRead();
  18. void on_btnJoin_clicked();
  19. void on_btnExit_clicked();
  20. private:
  21. Ui::Widget *ui;
  22. private:
  23. QUdpSocket *m_udpSocket = nullptr;
  24. QHostAddress groupAddr; //组播地址
  25. };
  26. #endif // WIDGET_H
  1. #include "widget.h"
  2. #include "ui_widget.h"
  3. #include <QHostInfo>
  4. Widget::Widget(QWidget *parent) :
  5. QWidget(parent),
  6. ui(new Ui::Widget)
  7. {
  8. ui->setupUi(this);
  9. //本地主机名
  10. QString hostName = QHostInfo::localHostName();
  11. m_udpSocket = new QUdpSocket(this);
  12. //socket QAbstractSocket::MulticastTtlOption值为1,MulticastTtlOption是
  13. //组播的数据的生存期,数据报没跨1个路由就会减1.表示多播数据报只能在同一路由下的局域网内传播
  14. m_udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,1);
  15. connect(m_udpSocket,&QUdpSocket::readyRead,this,&Widget::on_readyRead);
  16. }
  17. Widget::~Widget()
  18. {
  19. delete ui;
  20. }
  21. void Widget::on_btnClear_clicked()
  22. {
  23. ui->plainTextEdit->clear();
  24. }
  25. void Widget::on_btnSend_clicked()//组播
  26. {
  27. //目标端口
  28. quint16 groupPort = ui->spinBindPort->value();
  29. QString msg = ui->lineEdit->text();
  30. QByteArray str = msg.toUtf8();
  31. //发出数据报
  32. m_udpSocket->writeDatagram(str,groupAddr,groupPort);
  33. ui->plainTextEdit->appendPlainText("[multicast] "+msg);
  34. }
  35. void Widget::on_readyRead()
  36. {
  37. while(m_udpSocket->hasPendingDatagrams())
  38. {
  39. QByteArray data;
  40. data.resize(m_udpSocket->pendingDatagramSize());
  41. QHostAddress peerAddr;
  42. quint16 peerPort;
  43. m_udpSocket->readDatagram(data.data(),data.size(),&peerAddr,&peerPort);
  44. QString str = data.data();
  45. QString peer = "[From ] +"+peerAddr.toString()+":"+QString::number(peerPort)+"] ";
  46. ui->plainTextEdit->appendPlainText(peer+str);
  47. }
  48. }
  49. void Widget::on_btnJoin_clicked()
  50. {
  51. QString IP = ui->comboBox->currentText();
  52. groupAddr = QHostAddress(IP);
  53. quint16 groupPort = ui->spinBindPort->value();
  54. //加入组播之前,必须先绑定端口,端口为多播组统一的一个端口。
  55. if(m_udpSocket->bind(QHostAddress::AnyIPv4,groupPort,QUdpSocket::ShareAddress))
  56. {
  57. //加入组播
  58. m_udpSocket->joinMulticastGroup(groupAddr);
  59. ui->plainTextEdit->appendPlainText("**加入组播成功");
  60. ui->plainTextEdit->appendPlainText("**组播IP: "+ IP);
  61. ui->plainTextEdit->appendPlainText("**绑定端口: "+QString::number(groupPort));
  62. ui->btnJoin->setEnabled(false);
  63. ui->btnExit->setEnabled(true);
  64. ui->comboBox->setEnabled(false);
  65. }
  66. else
  67. {
  68. ui->plainTextEdit->appendPlainText("**绑定端口失败");
  69. }
  70. }
  71. void Widget::on_btnExit_clicked()
  72. {
  73. //退出组播
  74. m_udpSocket->leaveMulticastGroup(groupAddr);
  75. //解除绑定
  76. m_udpSocket->abort();
  77. ui->btnJoin->setEnabled(true);
  78. ui->btnExit->setEnabled(false);
  79. ui->comboBox->setEnabled(true);
  80. ui->plainTextEdit->appendPlainText("**已退出组播");
  81. }

文章转自博客园(商君治国安邦之张莽):QT UDP通信聊天程序(单播、广播、组播)

本文福利,莬费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击莬费领取↓↓ 

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

闽ICP备14008679号