0
点赞
收藏
分享

微信扫一扫

51-2 万字长文,深度解读端到端自动驾驶的挑战和前沿

逸省 2024-02-21 阅读 18

一、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

在这里插入图片描述

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

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


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

举报

相关推荐

0 条评论