QT UDP通信(单播、广播、组播)
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地址设置不同,多播模式需要加入多播组,实现方式有较大差异。
2.单播/广播
本机运行两个实例需要绑定不同的端口,例如实例A绑定端口2000,实例B绑定端口3000,实例A向实例B发送数据时,需要指定实例B所在主机的IP地址、绑定端口作为目标地址和目标端口,这样实例B才能接收到数据报。如果在不同的计算机运行,则可以使用相同的端口。
- 要实现数据接收,必须先使用QUdpSocket::bind()绑定一个端口,用于监听传入的数据报。解除绑定则使用abort()函数。
- writeDatagram()函数向一个目标用户发送消息时,需要指定目标地址和端口。
- 在广播消息时,只需要将目标地址更换为一个特殊地址,即广播地址QHostAddress::Broadcast,一般为255.255.255.255
- 发送的数据报是QByteArray类型的字节数组,数据报的长度一般不超过512字节,可以是文本,也可以是二进制数据。
- 接收到数据报后会发射readyRead()信号。
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QUdpSocket>namespace Ui {
class Widget;
}class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = 0);~Widget();private slots:void on_btnBind_clicked();void on_btnUnBind_clicked();void on_btnClear_clicked();void on_btnQuit_clicked();void on_btnSend_clicked();void on_btnBroadcast_clicked();void on_readyRead();
private:Ui::Widget *ui;private:QUdpSocket *m_udpSocket = nullptr;
};#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include <QHostInfo>Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);//本地主机名QString hostName = QHostInfo::localHostName();//本机IP地址QHostInfo hostInfo = QHostInfo::fromName(hostName);//IP地址列表QList<QHostAddress> addrList = hostInfo.addresses();for(int i=0;i<addrList.count();i++){QHostAddress host = addrList.at(i);if(QAbstractSocket::IPv4Protocol == host.protocol()){QString ip = host.toString();ui->comboBox->addItem(ip);}}m_udpSocket = new QUdpSocket(this);connect(m_udpSocket,&QUdpSocket::readyRead,this,&Widget::on_readyRead);}Widget::~Widget()
{delete ui;
}void Widget::on_btnBind_clicked()
{//本机UDP端口qint16 port = ui->spinBindPort->value();if(m_udpSocket->bind(port)){ui->plainTextEdit->appendPlainText("**已成功绑定");ui->plainTextEdit->appendPlainText("**绑定端口: "+QString::number(m_udpSocket->localPort()));ui->btnBind->setEnabled(false);ui->btnUnBind->setEnabled(true);}else{ui->plainTextEdit->appendPlainText("**绑定失败");}
}void Widget::on_btnUnBind_clicked()
{//解除绑定m_udpSocket->abort();ui->btnBind->setEnabled(true);ui->btnUnBind->setEnabled(false);ui->plainTextEdit->appendPlainText("**已解除绑定");
}void Widget::on_btnClear_clicked()
{ui->plainTextEdit->clear();
}void Widget::on_btnQuit_clicked()
{}void Widget::on_btnSend_clicked()//单播
{//目标IPQString dstIp = ui->comboBox->currentText();QHostAddress dstAddr(dstIp);//目标端口quint16 dstPort = ui->spinDstPort->value();QString msg = ui->lineEdit->text();QByteArray str = msg.toUtf8();//发出数据报m_udpSocket->writeDatagram(str,dstAddr,dstPort);ui->plainTextEdit->appendPlainText("[out] "+msg);
}void Widget::on_btnBroadcast_clicked()//广播
{quint16 dstPort = ui->spinDstPort->value();QString msg = ui->lineEdit->text();QByteArray str = msg.toUtf8();//发出数据报m_udpSocket->writeDatagram(str,QHostAddress::Broadcast,dstPort);ui->plainTextEdit->appendPlainText("[Broadcast] "+msg);
}void Widget::on_readyRead()
{//是否还有待读取的传入数据报while(m_udpSocket->hasPendingDatagrams()){QByteArray data;//返回待读取的数据报的字节数data.resize(m_udpSocket->pendingDatagramSize());QHostAddress peerAddr;quint16 peerPort;//读取数据报的内容m_udpSocket->readDatagram(data.data(),data.size(),&peerAddr,&peerPort);QString str = data.data();QString peer = "[From ] +"+peerAddr.toString()+":"+QString::number(peerPort)+"] ";ui->plainTextEdit->appendPlainText(peer+str);}
}
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完全相同。
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QUdpSocket>namespace Ui {
class Widget;
}class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = 0);~Widget();private slots:void on_btnClear_clicked();void on_btnSend_clicked();void on_readyRead();void on_btnJoin_clicked();void on_btnExit_clicked();private:Ui::Widget *ui;private:QUdpSocket *m_udpSocket = nullptr;QHostAddress groupAddr; //组播地址
};#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include <QHostInfo>Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);//本地主机名QString hostName = QHostInfo::localHostName();m_udpSocket = new QUdpSocket(this);//socket QAbstractSocket::MulticastTtlOption值为1,MulticastTtlOption是//组播的数据的生存期,数据报没跨1个路由就会减1.表示多播数据报只能在同一路由下的局域网内传播m_udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,1);connect(m_udpSocket,&QUdpSocket::readyRead,this,&Widget::on_readyRead);}Widget::~Widget()
{delete ui;
}void Widget::on_btnClear_clicked()
{ui->plainTextEdit->clear();
}void Widget::on_btnSend_clicked()//组播
{//目标端口quint16 groupPort = ui->spinBindPort->value();QString msg = ui->lineEdit->text();QByteArray str = msg.toUtf8();//发出数据报m_udpSocket->writeDatagram(str,groupAddr,groupPort);ui->plainTextEdit->appendPlainText("[multicast] "+msg);
}void Widget::on_readyRead()
{while(m_udpSocket->hasPendingDatagrams()){QByteArray data;data.resize(m_udpSocket->pendingDatagramSize());QHostAddress peerAddr;quint16 peerPort;m_udpSocket->readDatagram(data.data(),data.size(),&peerAddr,&peerPort);QString str = data.data();QString peer = "[From ] +"+peerAddr.toString()+":"+QString::number(peerPort)+"] ";ui->plainTextEdit->appendPlainText(peer+str);}
}void Widget::on_btnJoin_clicked()
{QString IP = ui->comboBox->currentText();groupAddr = QHostAddress(IP);quint16 groupPort = ui->spinBindPort->value();//加入组播之前,必须先绑定端口,端口为多播组统一的一个端口。if(m_udpSocket->bind(QHostAddress::AnyIPv4,groupPort,QUdpSocket::ShareAddress)){//加入组播m_udpSocket->joinMulticastGroup(groupAddr);ui->plainTextEdit->appendPlainText("**加入组播成功");ui->plainTextEdit->appendPlainText("**组播IP: "+ IP);ui->plainTextEdit->appendPlainText("**绑定端口: "+QString::number(groupPort));ui->btnJoin->setEnabled(false);ui->btnExit->setEnabled(true);ui->comboBox->setEnabled(false);}else{ui->plainTextEdit->appendPlainText("**绑定端口失败");}
}void Widget::on_btnExit_clicked()
{//退出组播m_udpSocket->leaveMulticastGroup(groupAddr);//解除绑定m_udpSocket->abort();ui->btnJoin->setEnabled(true);ui->btnExit->setEnabled(false);ui->comboBox->setEnabled(true);ui->plainTextEdit->appendPlainText("**已退出组播");
}
相关推荐:UDP多线程Server
QT UDP通信(单播、广播、组播)相关推荐
- 单播 广播 组播_【技术解析】关于组播概念那些你需要知道的~
点击蓝字关注我 今天,小盟带大家继续学习一下组播知识~ 一.IGMP Message 1.组成员一旦开启IGMP,会自动发送Membership Report消息到叶路由器 2.IGMPv2版本,组成 ...
- 单播 广播 组播_组播概念3
一.IGMP Message 1.组成员一旦开启IGMP,会自动发送Membership Report消息到叶路由器 2.IGMPv2版本,组成员退出组会发送leave消息,IGMPv1不会 3.也就 ...
- 单播 广播 组播区别
一:通信方式分类 在IPv4网络中,主机可采用的通信方式有如下三种: 1.单播:单台主机与单台主机之间的数据通信 带宽端口有多少台就发多少个数据 2.广播:单台主机向网络中所有主机发送数据包的过程 发 ...
- HCIA-RS自用笔记(9)数据转发过程、单播/多播/组播
数据转发过程(7/13,29min) 网关(Gateway) 不同网络的主机需要通讯,首先要把数据转发给网关,网关代表一条缺省路由 查看Windows主机路由表: C:\Users\Admin> ...
- 单播,组播,广播的区别
单播,组播,广播的区别 单播"(Unicast)."多播"(Multicast)和"广播"(Broadcast)这三个术语都是用来描述网络节点之间通讯 ...
- Java实现单播,组播,广播
单播.组播.广播介绍:https://blog.csdn.net/ahou2468/article/details/86526509 目录 1.单播.组播.广播关键类说明 2.单播和广播的具体实现 2 ...
- IP网络通信的单播、组播和广播
一.判断两台设备是否在同一局域网内 查看两台设备的ip4地址和子网掩码MASK. 若MASK不一样,则不在同一局域网内. 若MASK一样,分别计算IP&MASK.若二者相同,则在同一局域网,否 ...
- 单播、组播、广播三者之间的区别
单播.组播.广播其实是IPv4定义的三种流量类型 - 单播流量:一个人发送
- 【TCP/IP】单播与组播
[TCP/IP]单播与组播 三种IP地址: 单播地址.广播地址和组播地址 广播和多播仅应用于UDP. TCP是一个面向连接的协议,TCP一定是点对点的,一点是两个主机来建立连接的,TCP肯定是单播.只 ...
- 判断mac地址单播还是组播(shell脚本)
MAC地址是以太网二层使用的一个48bit(6字节十六进制数)的地址,用来标识设备位置.MAC地址分成两部分,前24位是组织唯一标识符(OUI, Organizationally unique ide ...
最新文章
- hadoop容灾能力测试
- xxx in ‘Anonymous class derived from xxx clashes with ‘call(T)‘ in xxx attempting to use incompati
- 是否可以将 json 反序列化为 dynamic 对象?
- KVM复制虚拟机,KVM克隆虚拟机
- 张文宏:WHO新型冠状病毒的传言和事实
- 【IDEA】关于 IDEA 中新建 web 项目的 webapp 文件夹没有小蓝点 ,启动服务,访问不到解决方案
- openresty lua集成kafka
- Memcache与Redis的区别
- 最新csdn有奖任务答案
- MATLAB小技巧(28)模糊综合评价
- 鉴源实验室丨车载ECU嵌入式软件的测试入门
- DIY一款600元成本的电路板热成像故障分析仪
- crt测试显示器软件,MonitorTest(显示器性能测试软件)
- Python类传参报错-TypeError:takes 2 positional arguments but 3 were given
- Java将OFD文件转PDF文件
- 百度智能云OCR获取APIKey和SecretKey
- qt 频谱 音乐播放器
- 传统优化方法:枚举法、启发式算法和搜索算法
- Spring入门-1-基本配置和IOC、DI
- 1.1、SR(Segment Routing Over MPLS) 介绍