总结QUdpSocket组播数据发不出去问题

文章介绍了在Qt中进行网络编程时的几个关键设置,包括绑定发送端口以适应严格防火墙环境,设置IP包的TimeToLive值以确保穿越复杂网络,以及在多网卡环境中如何指定组播接口。同时,提到了在Windows和Linux环境下使用C标准库解决Qt未提供的一些功能,并讨论了本地组播数据的回环问题及其在不同系统中的行为差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个事是有人问的问题,把常讲的三个原因总结出来Mark一下。

1、绑定发送端口和端口复用

有的业务系统要求发送socket也要绑定发送端口,一般来说,发送的socket可以不绑定端口,系统会随机指定一个,有的系统防火墙或者路由器设置要求严格,就要在发送数据之前设置一下。

QUdpSocket sendSock;
bool ok  = sendSock.bind(QHostAddress::AnyIPv4,sendPort,QUdpSocket::ShareAddress| QUdpSocket::ReuseAddressHint);

第一个参数为啥要设置AnyIPv4,因为主要目的只是设置发送端口,其实在这里跟哪个网卡关系还不大。

第二个参数就是要绑定的发送端口

后面的参数,是说要端口复用的意思,很多时候这个发送端口可能有别的进程或线程也在用。要这样设置一下。

2、设置IP包的Time To Live值(ttl)

通过tcpdump或者wireshark可以抓包看看自己发送得数据包的ttl值多大。默认是1,过的业务系统网络稍微复杂一些就出不去了。(tcpdump 用上参数-vxx就能看见详细信息了。)

 //设置ttl
        char ttl = 16;
        sendSock.setSocketOption(QAbstractSocket::MulticastTtlOption,ttl);

3、多网卡环境下,设置一下发送给组播的“脸面”Interface



// inet_addr将字符串形式的IP转换为整数
    in_addr       addr;
    addr.s_addr = inet_addr(localIP.toStdString().c_str());
    //为Socket设置组播Interface //绑定指定ip来接收组播组信息,可能是版本问题, Qt的QNetworkInterface也TM不好用,Qudpsocket还是要通过socketDescriptor回到C的标准库上
    int ret=0;
    ret = setsockopt( sendSocket.socketDescriptor(), IPPROTO_IP, IP_MULTICAST_IF,(const char*)&addr, sizeof(addr));

理论上,Qt也提供了这个setMulticastInterface函数,但可能是我写错了,或者qt版本问题,或者系统问题,我试了一下没成功,回到了标准库。

void QUdpSocket::setMulticastInterface(const QNetworkInterface
&iface) 对标的就是IP_MULTICAST_IF设置多播接口的问题,

这里要用C标准库的setsocketopt能解决这个“脸面”问题。不同操作系统记得包含各自的头文件

//不论是linux还是windows,Qt目前都没有加入SSM的函数,只能自己通过C的socket操作补全,指定源
#ifdef WIN32
// 注意不可以在<winsock2.h>之前包含"windows.h",否则会导入"winsock.h",里面宏的定义不一致
//#include "windows.h"
#include <winsock2.h>
#include <ws2tcpip.h>
//如果是VC6还需要自己定义一个ip_mreq_source结构体和#define IP_ADD_SOURCE_MEMBERSHIP 15
//struct ip_mreq_source {
//  struct in_addr imr_multiaddr;
//  struct in_addr imr_sourceaddr;
//  struct in_addr imr_interface;
//};
#else
//linux下的实现基本类似,区别仅是包含的头文件不同。win10下Qt5.9没问题。银河麒麟4.0.2下Qt5.7没问题
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>

#define closesocket close

typedef int     BOOL;
typedef unsigned int DWORD;
typedef int     SOCKET;

#define INVALID_SOCKET -1
#define FALSE   0
#define TRUE    1
#define stricmp strcasecmp
#define ERROR_SUCCESS           0x0
#endif

因为用了qt的network以外的库,在windows平台改下.pro文件


QT       += core gui network

//。。。
win32 {
LIBS += -lWs2_32
}

4、最后顺便说一下本地如果收不到自己发送的组播数据可能的“回环”loopback问题

sendSocket.setSocketOption(QAbstractSocket::MulticastLoopbackOption, 0); 

1是允许loopback模式(自发自收),0是阻止。

这个阻止还是允许,不同系统又不同的解释:

假如在同一台计算机上有两个应用程序,并且加入了同一个组播。这两个程序,一个允许回环,一个阻断回环,则会有如下现象:
windows下,允许方不能发向阻断方,但阻断方可以发向允许方;
linux下,允许方可以发向阻断方,但阻断方不能发向允许方。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值