赞
踩
UDP是轻量的、不可靠的、面向数据报、无连接的协议,它可以用于对可靠性要求不高的场合,与TCP通信不同,无需建立持久的socket连接。
QUdpSocket用于实现UDP通信,与QTcpSocket主要区别是,QUdpSocket以数据报传输数据,而不是以连续的数据流。发送数据使用writeDatagram(),数据报的长度一般少于512字节,每个数据报包含发送者和接收者的IP地址和端口等信息。
要进行UDP通信,首先需要bind函数绑定一个端口,用于接收传入的手机不能。当有数据报传入时会发射readyRead()信号,使用readDatagram()来读取接收到的数据报。
UDP消息传送有单播、广播、组播三种模式。
在单播、广播和多播下,UDP程序都是对等的,不像TCP那样分为客户端和服务器端。单播和广播的实现方式基本相同,只是数据报的目标IP地址设置不同,多播模式需要加入多播组,实现方式有较大差异。
本文福利,莬费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击莬费领取↓↓
本机运行两个实例需要绑定不同的端口,例如实例A绑定端口2000,实例B绑定端口3000,实例A向实例B发送数据时,需要指定实例B所在主机的IP地址、绑定端口作为目标地址和目标端口,这样实例B才能接收到数据报。如果在不同的计算机运行,则可以使用相同的端口。
- #ifndef WIDGET_H
- #define WIDGET_H
-
- #include <QWidget>
- #include <QUdpSocket>
-
- namespace Ui {
- class Widget;
- }
-
- class Widget : public QWidget
- {
- Q_OBJECT
-
- public:
- 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()//单播
- {
- //目标IP
- QString 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);
- }
- }
组播是主机之间“一对一组”的通信模式,当多个客户端加入由一个组播地址定义的多播组之后,客户端向组播地址和端口发送数据报,组内成员都可以接收到,类似QQ群。
UDP组播必须使用一个组播地址。组播地址是D类IP地址,有特定的地址段。多播组可以是永久的也可以是临时的。永久多播组保持不变的是它的IP地址,组内成员结构可以发生变化。
若在家庭或办公室局域网内测试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_OBJECT
-
- public:
- 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("**已退出组播");
- }
文章转自博客园(商君治国安邦之张莽):QT UDP通信聊天程序(单播、广播、组播)
本文福利,莬费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击莬费领取↓↓
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。