Qt由入门到放弃-QNetWork之QUdpSocket

目录

一、 QUdpSocket基本概念和相关函数

二、QUdpSocket广播

三、QUdpSocket组播


一、 QUdpSocket基本概念和相关函数

        QUdpSocket提供了UDP套接字API,用来接收和发送UDP数据报。

        QUdpSocket类最通用的使用方式是:用bind()函数绑定一个IP地址和端口Port,然后调用writeDatagram()和readDatagram()函数传输数据。

enum QUdpSocket::BindFlagflags QUdpSocket::BindMode 

        BindFlag 这些值可以组成不同的标志,传递给QUdpSocket::bind()函数来修改bind()的特性。BindMode 是typedef for QFlags<BindFlag>。它是BindFlag值得或操作。

常量定义

描述

QUdpSocket::ShareAddress

0x1

1、允许其他服务绑定同样的地址和端口

2、当多进程通过监听同一地址和端口,进而共享单个服务的负载时,将十分有用(例如:一个拥有几个预先建立的监听者的WEB服务器能够改善响应时间)。不过,由于任何服务都允许重新绑定(rebind),该选项应该引起某些安全上的考虑

3、需要注意的是,把该选项和ReuseAddressHint结合,也会允许你的服务重新绑定一个已存在的共享地址

4、在Unix上,该选项等同于SO_REUSEADDR;在Windows上,该选项被忽略

QUdpSocket::DontShareAddress

0x2

1、采用专有的方式绑定某个地址和端口,其他任何服务都不能再重新绑定

2、通过该选项,确保绑定成功,指定的服务将是地址和端口唯一监听者,就算是拥有ReuseAddressHint的服务也不允许重新绑定

3、在安全性上,该选项优于ShareAddress,但是在某些操作系统上需要管理员的权限才能运行

4、在Unix和Mac OS上,绑定地址和端口的默认行为是非共享,所以该选项会被忽略;在Windows上,等同于SO_EXCLUSIVEADDRUSE套接字选项

QUdpSocket::ReuseAddressHint

0x4

1、为QUdpSocke提供提示,即在地址和端口已经被其他套接字绑定的情况下,也应该试着重新绑定

2、在Unix上,该选项被忽略;在Windows上等同于SO_REUSEADDR 套接字选项

QUdpSocket::DefaultForPlatform

0x0

1、当前平台的默认选项

2、在Unix和Mac OS上,该选项等同于DontShareAddress + ReuseAddressHint;在Windows上等同于ShareAddress

        如果要使用QIODevice中的read(), readLine(), write()等函数,必须首先调用connectToHost()函数,直接建立一个和对方的连接

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

        只要向网络写入了一个数据报,SOCKET就产生一个bytesWritten()信号,如果仅仅是发送数据报,无需调用bind()。数据报到来,readyRead()信号被产生,此时hasPendingDatagrams()函数返回真(true)。调用pendingDatagramSize()获取第一个数据报的长度(size),readDatagram()读取数据报内容。

qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address = Q_NULLPTR, quint16 *port = Q_NULLPTR)
  1. 接收不大于maxSize字节的数据报并将其存储在数据中。发送方的主机地址和端口存储在address 地址和port 端口中(除非指针为0);成功时返回数据报的大小,否则返回-1
  2. 如果maxSize太小,数据报的其余部分将丢失,因此为避免数据丢失,请在读取数据报之前调用PendingDatagramSize()确定数据报的大小;
  3. 如果maxSize为0,则数据报将被丢弃
QUdpSocket *receiver;
//每当有数据报发送过来时,QUdpSocket都会发射readyRead信号,这样就可以在自定义的槽中读取数据
connect(receiver,SIGNAL(readyRead()),this,SLOT(processPendingDatagram()));
读取数据报
void Receiver::processPendingDatagram()
{
    while (m_pUdpSocket->hasPendingDatagrams())//如果有数据报需要读取
    {
    	//读数据包
            QByteArray datagram;
    	datagram.resize(m_pUdpSocket->pendingDatagramSize());
    	m_pUdpSocket->readDatagram(datagram.data(), datagram.size());
    } 
}

注意:接收到readyRead()信号后,应当读取该数据报,否则下一个数据报到来后将不再产生readyRead()信号。

        QHostAddress类提供一个IP地址。这个类提供一种独立于平台和协议的方式来保存IPv4和IPv6地址。QHostAddress通常与QTcpSocket、QTcpServer、QUdpSocket一起使用,来连接到主机或建立一个服务器。

枚举 QHostAddress::SpecialAddress:

常量 值 描述

QHostAddress::Null 0 空地址对象,相当于QHostAddress()。

QHostAddress::LocalHost 2 IPv4本地主机地址,相当于QHostAddress(“127.0.0.1”)。

QHostAddress::LocalHostIPv6 3 IPv6本地主机地址,相当于 QHostAddress(“::1”)。

QHostAddress::Broadcast 1 Pv4广播地址,相当于QHostAddress(“255.255.255.255”)。

QHostAddress::AnyIPv4 6 IPv4 any-address,相当于QHostAddress(“0.0.0.0”)。与该地址绑定的socket将只监听IPv4接口。

QHostAddress::AnyIPv6 5 IPv6 any-address,相当于QHostAddress(“::”)。与该地址绑定的socket将只监听IPv4接口。

QHostAddress::Any 4 双any-address栈,与该地址绑定的socket将侦听IPv4和IPv6接口。

二、QUdpSocket广播

        在使用QUdpSocket发送广播消息时,当发送端配有多个ip地址时,发送端需要绑定一个指定的ip地址才能实现向次局域网内的其他主机发送广播消息,否则其他主机不能收到;如果只是本机法送和接收消息,那么ip地址可以设置为 QHostAddress::LocalHost。接收端只需要绑定发送端指定的端口即可。

查找可用的广播地址:

QList<QNetworkInterface> interfaceList = QNetworkInterface::allInterfaces();
    foreach (QNetworkInterface interface, interfaceList)
    {
        qDebug() << interface.humanReadableName(); //打印网卡名称
        QList<QNetworkAddressEntry> entryList = interface.addressEntries();
        foreach(QNetworkAddressEntry entry, entryList)
        {
            QString str = entry.broadcast().toString();
            if(str != "")
            {
                  qDebug() << str; //打印可用的广播地址
            }
        }
    }

发送端:广播write发送数据应该绑定ip,否则多网卡发送不正确

QUdpSocket *sender;
QHostAddress addr;
QString ip = "192.168.66.66";
addr.setAddress(ip);
sender->bind(addr,5555,QUdpSocket::ShareAddress);
QByteArray datagram = ui->lineEdit->text().toLatin1();
sender->writeDatagram(datagram.data(),datagram.size(),QHostAddress::Broadcast,5556);//把数据写入报文并发送

接收端需保证有一个ip地址和服务端的绑定ip(192.168.66.XXX)在同一网段:

QUdpSocket *receiver;
receiver->bind(5556,QUdpSocket::ShareAddress);  //端口设置为server端设置的端口
//每当有数据报发送过来时,QUdpSocket都会发射readyRead信号,这样就可以在自定义的槽中读取数据
connect(receiver,SIGNAL(readyRead()),this,SLOT(processPendingDatagram()));
读取数据报
void Receiver::processPendingDatagram()
{
    QHostAddress addr; //服务器ip
    quint16 port;   //服务器发送的端口号
    while (receiver->hasPendingDatagrams())//如果有数据报需要读取
    {
    	//读数据包
            QByteArray datagram;
    	datagram.resize(receiver->pendingDatagramSize());
    	receiver ->readDatagram(datagram.data(), datagram.size(),&addr,&port);
           qDebug()<<"send addr="<<addr.toString(); //"192.168.66.66"
           qDebug()<<"send port="<<port;  //5555
           qDebug()<<"receive msg="<<datagram;
    } 
}

三、QUdpSocket组播

组播发送socket不需要加入组播,只要向组播地址发送数据:

QUdpSocket *sender;
QHostAddress multiAddr;
QString multiIp = "224.5.5.5"; //组播ip
quint16 sendPort = 11111;  //发送端口
quint16 receivePort = 22222;  //接收端口
multiAddr.setAddress(multiIp);
sender->bind(sendPort,QUdpSocket::ShareAddress);  //此处添加发送ip接收端接不到,绑定对应网卡取代
QByteArray datagram = ui->lineEdit->text().toLatin1();
sender->writeDatagram(datagram.data(),datagram.size(),multiAddr,receivePort);//把数据写入报文并发送

组播接收端:需要加入组播组,最好设置绑定的网卡

QUdpSocket *receiver;
QHostAddress multiAddr;
QString multiIp = "224.5.5.5"; //组播ip
quint16 receivePort = 22222;  //接收端口
multiAddr.setAddress(multiIp);
bool result = receiver->bind(QHostAddress::Any, receivePort , QUdpSocket::ShareAddress);
if(!result)
{
    qDebug()<<"bind failed";
}
bool result1 = receiver->joinMulticastGroup(multiAddr); //加入组播组
if(!result1)
{
    qDebug()<<"joinMuticastGroup failed";
}
//每当有数据报发送过来时,QUdpSocket都会发射readyRead信号,这样就可以在自定义的槽中读取数据
connect(receiver,SIGNAL(readyRead()),this,SLOT(processPendingDatagram()));
//读取数据报

void Receiver::processPendingDatagram()
{
    QHostAddress addr; //服务器ip
    quint16 port;   //服务器发送的端口号
    while (receiver->hasPendingDatagrams())//如果有数据报需要读取
    {
    	//读数据包
            QByteArray datagram;
    	datagram.resize(receiver->pendingDatagramSize());
    	receiver->readDatagram(datagram.data(), datagram.size(),&addr,&port);
           qDebug()<<"send addr="<<addr.toString(); //"192.168.66.66"
           qDebug()<<"send port="<<port;  //5555
           qDebug()<<"receive msg="<<datagram;
    } 
}

 

  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Qt调用新版HP-Socket实现UDP客户端的步骤如下: 1.下载并安装新版HP-Socket,可以在官网上下载最新版本的HP-Socket。 2.创建一个Qt的控制台应用程序,选择C++语言。 3.将HP-Socket的头文件和库文件添加到Qt项目中。 4.在Qt的main函数中调用以下代码: ```cpp HPSocket::Startup(); auto pUdpClient = CHPSocket::Construct<CUdpClient>(nullptr); pUdpClient->SetSocketListener(new CUDPSocketListener()); pUdpClient->SetRemoteAddress("127.0.0.1", 5555); if (!pUdpClient->Start()) { qDebug() << "UDP client start failed"; return -1; } char szBuffer[] = "hello world!"; int iLength = strlen(szBuffer); int iResult = pUdpClient->Send(szBuffer, iLength); if (iResult != iLength) { qDebug() << "UDP client send failed"; } HPSocket::Cleanup(); ``` 5.创建一个CUDPSocketListener类,继承于IUdpClientListener,并重写相应的事件回调函数: ```cpp class CUDPSocketListener : public IUdpClientListener { public: virtual EnHandleResult OnConnect(ITcpClient* pSender, CONNID dwConnID) override { return HR_OK; } virtual EnHandleResult OnReceive(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength) override { return HR_OK; } virtual EnHandleResult OnClose(ITcpClient* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode) override { return HR_OK; } }; ``` 6.编译并运行Qt程序,即可实现UDP客户端的功能。 需要注意的是,在使用新版HP-Socket时,需要在程序的开头调用HPSocket::Startup()函数,在程序结束时调用HPSocket::Cleanup()函数。此外,在使用CUdpClient时,需要设置远程地址和端口号,然后调用Start()函数启动客户端。发送数据时,可以调用Send()函数发送数据。接收数据时,需要在CUDPSocketListener类中重写OnReceive()函数,通过pData参数获取接收到的数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值