QT网络编程之UDP

1 UDP通信概述QUdpSocket类

  • UDP协议(用户数据报协议)是不可靠的、轻量的、无连接的协议。与TCP不同UDP通信时,每次发送数据报协议都要指定目标地址和端口。
  • QT中通过QUdpSocket类实现UDP通信,它以数据报传输数据,而不是连续的字节流。发送数据报时用writeDatagram函数向指定的地址和端口发送数据报,长度一般小于512Byte。接收数据时,要先用bind函数绑定本机的一个端口,当数据报到来时,readyRead信号被触发,使用readDatagram函数来读取接收到的数据报。
  • UDP消息传送有三种模式:单播模式(unicast)、广播模式(boardcast)、组播模式(multicast),TCP只有单播模式。另外UDP的两端是对等的,不像TCP那样分为客户端和服务器。
  • 单播指一个UDP客户端发出的数据只发送到另一个指定地址和端口的UDP客户端,是一对一的数据传输。
  • 广播指一个UDP客户端发出的数据,在同一网络范围的其它所有UDP客户端都可以收到,只需在数据报中指定接收端地址为QHostAddress::Broadcast,一般广播地址为255.255.255.255
  • 组播也称多播,UDP客户端加入到另一个组播IP地址指定的多播组中,成员向组播地址发送的数据报组内成员都可以接收到,类似于QQ群。
  • QUdpSocket类的主要接口函数:
bool QAbstractSocket::bind(quint16 port = 0, BindMode mode = DefaultForPlatform);
qint64 QUdpSocket::writeDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port);
qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port);
bool QUdpSocket::hasPendingDatagrams() const;
qint64 QUdpSocket::pendingDatagramSize() const;
qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address = Q_NULLPTR, quint16 *port = Q_NULLPTR);
bool QUdpSocket::joinMulticastGroup(const QHostAddress &groupAddress);
bool QUdpSocket::leaveMulticastGroup(const QHostAddress &groupAddress);

调用bind函数在本机绑定指定端口port,用于UDP通信。
writeDatagram函数向指定的地址host和端口port发送数据报datagram,返回成功发送的字节数,数据报不要太长,不要超过512Byte。
hasPendingDatagrams函数返回true,当至少有一个数据报需要读取。
pendingDatagramSize函数第一个待读取的数据报的大小Byte。
readDatagram函数用来读取数据报,address 和port指定发送者的地址和端口号,最多读maxSize个Byte,返回成功读取的字节数。
joinMulticastGroup函数使socket加入一个多播组groupAddress。
leaveMulticastGroup函数使socket离开多播组groupAddress。

2 示例

2.1 单播

//udpClient.cpp
QUdpSocket  *udpSocket = new QUdpSocket(this);//用于与连接的客户端通讯的QTcpSocket
udpSocket->bind(port);//绑定一个本机的端口,用于接收他人传来的数据报

connect(udpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));//指示状态变化
connect(udpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));//数据报到来时readyRead信号触发

void MainWindow::onSocketReadyRead()
{//读取收到的数据报
    while(udpSocket->hasPendingDatagrams())//有未读的数据报
    {
        QByteArray   datagram;
        datagram.resize(udpSocket->pendingDatagramSize());//将datagram初始化为到来的数据报的大小

        QHostAddress peerAddr;
        quint16 peerPort;
        udpSocket->readDatagram(datagram.data(),datagram.size(),&peerAddr,&peerPort);
        QString str=datagram.data();//数据是字符串的话才转化
    }
}

void MainWindow::on_btnSend_clicked()
{//发送数据报消息
    QString targetIP=ui->comboTargetIP->currentText(); 
    QHostAddress targetAddr(targetIP);//目标IP
    quint16 targetPort=ui->spinTargetPort->value();//目标port

    QString  msg=ui->editMsg->text();//发送的消息内容
    QByteArray  str=msg.toUtf8();//转化为QByteArray  
    udpSocket->writeDatagram(str,targetAddr,targetPort); //发出数据报
}

udpSocket->abort(); //解除绑定

2.2 广播

发出广播消息时,writeDatagram函数中指定的地址改为QHostAddress::Broadcast,别的和单播的情形相同。

void MainWindow::on_btnBroadcast_clicked()
{ //发送广播消息
    quint16 targetPort=ui->spinTargetPort->value(); //目标端口
    QString  msg=ui->editMsg->text();
    
    QByteArray  str=msg.toUtf8();
    udpSocket->writeDatagram(str,QHostAddress::Broadcast,targetPort);
}

2.3 组播

UDP组播是主机间一对一组的通信模式,当多个客户端加入由一个组播地址定义的多播组后,客户端向这个组播地址和端口发送的UDP数据报,组内成员都可以接收到。组播地址是D类IP地址,有特定的地址段,这里不再详细介绍。
239.0.0.0~239.255.255.255为本地管理组播地址范围,家庭办公室局域网测试UDP组播选用这一范围。

QUdpSocket  *udpSocket = new QUdpSocket(this);//用于与连接的客户端通讯的QTcpSocket
QHostAddress    groupAddress;//组播地址
//Multicast路由层次,1表示只在同一局域网内,默认值是1,表示数据包只能在本地的子网中传送。
//组播TTL: 生存时间,每跨1个路由会减1,多播无法跨过大多数路由所以为1
udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,1);
connect(udpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));

//readyRead槽函数,读取数据报
void MainWindow::onSocketReadyRead()
{
    while(udpSocket->hasPendingDatagrams())
    {
        QByteArray   datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        QHostAddress peerAddr;
        quint16 peerPort;
        udpSocket->readDatagram(datagram.data(),datagram.size(),&peerAddr,&peerPort);
        QString str=datagram.data();
    }
}

//加入组播
QString IP=ui->comboIP->currentText();
QHostAddress groupAddress=QHostAddress(IP);//多播组地址
quint16 groupPort=ui->spinPort->value();//端口
if (udpSocket->bind(QHostAddress::AnyIPv4, groupPort, QUdpSocket::ShareAddress))//先绑定端口
	udpSocket->joinMulticastGroup(groupAddress); //加入多播组

//发送组播消息
quint16 groupPort=ui->spinPort->value();
QString msg=ui->editMsg->text();
QByteArray datagram=msg.toUtf8();
udpSocket->writeDatagram(datagram.data(),datagram.size(),groupAddress,groupPort);

//退出组播
udpSocket->leaveMulticastGroup(groupAddress);
udpSocket->abort(); //解除绑定
  • 7
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值