关于在Windows上socket组播通信的一些问题

本文介绍了在Windows上进行组播通信时遇到的问题,如消息发送后接收方未接收到,发现是由于虚拟网卡引起的。作者提供了禁用虚拟网卡和使用`IP_ADD_MEMBERSHIP`指定发送网卡的方法,以及推荐了一个socket调试工具。

一、Windows上的组播通信

基本和linux上的socket编程一致,稍微有点区别

以下是我测验可以使用的代码,
客户端

// 广播处理回复消息回调
typedef void(*handMulticastRsp)(char* rspstr, int len);
// 发送组播消息
// buff 	发送内容
// len		发送内容长度
// groupIp	组播地址
// port		端口
// callbk	回调函数处理回复消息
// ms		等待回复超时时间
int multicast_sendmsg_wait(char* buff, int len, char* groupIp, int port,  handMulticastRsp callbk, unsigned int ms) {
    SOCKET socketfd = 0;
    int ret = 0;
    int selret = 0;

    if (NULL==buff || len<=0 || NULL==groupIp)
        return -TCPIPERR_CHECK_PARAM;
    // 检查IP的合法性

#if __WIN32
    WORD sockVersion=MAKEWORD(2,2);
    WSADATA wsaData;//WSADATA结构体变量的地址值
    if(WSAStartup(sockVersion, &wsaData)!=0)
    {
        printf("WSAStartup() error!");
        return 0;
    }
#endif

    // 创建套接字
    //socketfd = socket(AF_INET, SOCK_DGRAM|SOCK_NONBLOCK, 0);
    socketfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (INVALID_SOCKET==socketfd) {
        printf("创建套接字失败, errno %d\n", errno);
        WSACleanup();
        return -TCPIPERR_SOCKET_CREATE;
    }
    // 设置为非阻塞

    // 设置同主机还是跨主机
    //int iFlag = 1;	// 0-同一台主机 1-夸主机
    //ret = setsockopt(socketfd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&iFlag, sizeof(iFlag));

    //  设置发送地址,地址即是组播地址
    struct sockaddr_in cliaddr;
    memset(&cliaddr,0,sizeof(cliaddr));
    cliaddr.sin_family = AF_INET;
    cliaddr.sin_port = htons(10000); // 接收端需要绑定9999端口
    // 发送组播消息, 需要使用组播地址, 和设置组播属性使用的组播地址一致就可以
    inet_pton(AF_INET, groupIp, &cliaddr.sin_addr.s_addr);

    // 数据广播
    ret = sendto(socketfd, buff, len, 0, (struct sockaddr*)(&cliaddr), sizeof(struct sockaddr));
    if (ret<=0) {
        printf("发送组播失败, errno %d\n", errno);
        ret = -TCPIPERR_SENDMSG;
    }

#if 0
#if 0
    if (ms>0) {
        // 指定了等待时间,等待回复消息,这里如果不需要知道发送端地址,都指定为空
        ret = recvfrom(socketfd, buff, len, 0, NULL, NULL);
        if (-1==ret) {
            printf("接收消息失败, errno %d\n", errno);
            ret = -TCPIPERR_RECVMSG;
        }
    }
    #else
    while ((ret=recvfrom(socketfd, buff, len, 0, NULL, NULL))>0)
    {
        printf("获取消息 %s, ret %d\n", buff, ret);
    }
    printf("<== ret %d\n", ret);
#endif
#endif

    fd_set rfds;
    struct timeval tv;
    FD_ZERO(&rfds);
    FD_SET(socketfd, &rfds);
    // 设置超时时间
    tv.tv_sec = 0;
    tv.tv_usec = 10000;

    // 预计读取数据为超时
    ret = -TCPIPERR_WAITRECV_TIMEOUT;
start_select:
    selret = select(socketfd+1, &rfds, NULL, NULL, &tv);
    if (-1==selret) {
        ret = -TCPIPERR_SELECT;
    } else if (0 == selret) {
        printf("等待数据超时\n");
        //ret = -TCPIPERR_WAITRECV_TIMEOUT;
    } else {
        // >0,有数据
        ret = recvfrom(socketfd, buff, len, 0, NULL, NULL);
        if (-1==ret) {
            ret = -TCPIPERR_RECVMSG;
            goto error_set;
        }
        // printf("获取消息 %s, ret %d\n", buff, ret);

        if (ret>0 && NULL!=callbk) {
            callbk(buff, ret);
        }
        // 标记读取成功,
        ret = 0;
        // 重新监听是否有数据返回
        goto start_select;
    }

error_set:
    closesocket(socketfd);
    WSACleanup();
    return ret;
}


二、遇到的问题

1、发送组播消息,另一台设备监听组播消息,然而,收不到消息

结论:虚拟网卡导致的组播监听异常,监听到虚拟网卡上了

# cmd 查询加入网络情况
netsh interface ipv4 show joins

在这里插入图片描述

随后我吧其他虚拟网卡禁用,开发板就能正常收到组播数据了。
在这里插入图片描述

另一种解决方法
在发送组播消息的时候,指定网卡ip,加入组播
添加如下代码

// 设置指定网卡发送
struct ip_mreq mreq; // 多播地址结构体
memset((void*)&mreq, 0, sizeof(struct ip_mreq));
mreq.imr_multiaddr.s_addr = inet_addr(groupIp);
// 这里选择默认网卡或者指定网卡
if (NULL==if_ip)
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
else
    mreq.imr_interface.s_addr = inet_addr(if_ip);
// 加入组
ret = setsockopt(socketfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq));
if (ret<0) {
    printf("add membership, errno %d\n", errno);
    ret = -1;
    goto error_set;
}

感谢@dreamwatchman提供的解决思路
Linux、windows组播通信所遇坑集合


推荐一个好用的工具
socket调试工具

内容概要:本文围绕可变桨叶四旋翼无人机的规范控制点对点运动模拟展开,重点研究优化推力分配策略在翻转动作中的应用性能比较。通过Matlab代码实现,构建了四旋翼动力学模型,并设计了多种控制算法以实现精确的姿态调整轨迹跟踪。研究对比了不同推力分配方案在执行高机动性翻转动作时的稳定性、能耗效率响应速度,旨在提升无人机在复杂飞行任务中的动态性能控制精度。该仿真研究为无人机飞控系统的设计优化提供了理论依据和技术支持。; 适合人群:具备一定自动控制理论基础和Matlab编程能力,从事无人机控制、飞行器动力学或机器人系统研究的科研人员及研究生。; 使用场景及目标:① 实现四旋翼无人机在三维空间中的精确点对点运动控制;② 对比分析不同推力分配策略在执行翻转等高难度动作时的控制效果能耗表现,优化飞行性能;③ 为无人机自主飞行、特技飞行及复杂环境下的机动控制提供算法验证平台。; 阅读建议:此资源以Matlab仿真为核心,建议读者结合相关控制理论知识,深入理解代码实现细节,重点关注动力学建模、控制律设计推力分配模块。在学习过程中,应动手调试参数,复现文中翻转动作的仿真结果,并尝试拓展至其他复杂飞行任务,以加深对无人机控制机理的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值