关于QT UDP组播的几个问题

UDP组播时最好不要提客户端/服务端的概念,而是提发送端/接收端的概念,避免出现逻辑理解混乱。发送端也需要接收,实际使用的过程中还是得根据业务提服务端/客户端。组播时A端和B端,都可能收发,把它们都加入组播组就可以了,能够达到既能接收也能发送的要求。

注意:如果A端和B端,在同一台机器上,应当注意bind时的端口冲突。

大家在使用QT UDP时,可能会出现下面的情况:

1.接收不到数据

一般我们会这样写:

m_udpSocket = new QUdpSocket();
m_udpSocket->bind(QHostAddress::AnyIPv4,8083,QUdpSocket::ShareAddress);
m_udpSocket->setSocketOption(QAbstractSocket::MulticastLoopbackOption,0);
m_udpSocket->joinMulticastGroup(m_McastAddr);
connect(m_udpSocket,SIGNAL(readyRead()),this ,SLOT(processPendingDatagrams()));

在接收端加入语句

m_udpSocket->setSocketOption(QAbstractSocket::MulticastLoopbackOption,0);

代表禁止本机回环接收,自发自收是不能实现的,值应当改为1。
bind Ip时使用QHostAddress::AnyIPv4是必要的。

2.还是接收不到数据

此时应当考虑网卡是否选对,如果选择了类似loopback_1这样的网卡,就只能在本机(127.0.0.1)上收发了,如果A端和B端分别在两台机器上,除了两台机器都要在一个网段(如192.168.9.0)中,还要选择在这个网段的网卡,因为现在的机器一般都有有线和无线网卡。通过QNetworkInterface可以查看活跃的且支持组播的网卡。

QNetworkInterface(name = "wireless_0",flags = IsUp IsRunning CanBroadcast CanMulticast)

以上代表一个无线网卡可用。像下面这样设置

udp->setMulticastInterface(intf);

另外如果A端和B端分别处于2个不同的网段中,也就是说组播要跨越路由器,组播是可以跨网段的,需要IGMP协议支持,但是本次我的测试,没有成功,没有路由器的访问权限,也就放弃了。我想应当需要到路由器上去设置,查看启用IGMP协议的接口

命令show ip igmp interface //这个是来自网上有待验证
3.readyRead触发后,忘了读导致的问题

我在测试时,槽函数中只写了打印信息,没有调用readDatagram读取数据,A端连续发送数据,B端的readyRead信号只抛出了一次,而后无论A端发多少次,B端始终不抛readyRead信号了。

这是因为QT的socket在抛出readyRead之前,会将数据读取到自己的缓冲区中,如果A端一直发,而B端并不从槽函数中读取数据,那么Qt就会不断的从系统缓冲区中读出数据放置自己内部缓冲区,最后肯定会出现堆栈满的情况,系统异常退出。

同时,第一次数据到来,触发了readyread信号,如果readyRead的槽函数没有来得及执行,而新的数据又来了,也许来了很多次(在QTcpSocket缓存没有满的情况下,满的情况下系统不会再发数据给应用),那么,都将会只再触发一次readyRead信号。

参考https://blog.csdn.net/Dengdew/article/details/79065608

4.关于readDatagram方法

该方法用于读取UDP数据报,第2个参数是读取多少数据(或者说叫buffer大小),如果这个值小于QUdpSocket缓冲区中可读数据的长度,那么剩下没有读取完的数据,将会被丢弃,需要格外注意。

5.Windows能接收,Linux接收不到

以中标麒麟举例,它的防火墙中默认情况下,我们设置的端口号,是没有权限的,所以要在防火墙中放开限制;那么其他Linux操作系统可能也是这种问题。

题外话:connectToHost方法在QUdpSocket中的问题

如果QUdpSocket的对象不调用connectToHost的方法,连接一个对等的用户(peer),将无法使用write/read等标准IO函数,只能使用readDatagram/writeDatagram方法。但是请注意connectToHost给一个无法ping通的IP地址,仍然能够抛出connected信号和hostFound信号,这跟Tcp很不一样。

题外话:编译错误,报socket在不同的线程使用

一般应用中我们会在线程中接收数据,然后用另一个线程解析数据,以达到防止主线程卡死的问题;无论是继承QThread重载run函数;还是将接收对象moveToThread,都需要注意是在主线程还是在子线程中创建的QUdpSocket;

因为QUdpSocket是不支持跨线程使用的,如果首先接收对象构造函数中创建QUdpSocket,然后再将接收对象moveToThread,就会出现这个问题,因为此时线程还没有启动,你就已经new了QUdpSocket了。所以要等到线程的started()信号发出后,再创建QUdpSocket。

  • 10
    点赞
  • 114
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值