zoukankan      html  css  js  c++  java
  • Windows多网卡UDP广播问题

    最近在项目中遇到一个关于UDP广播的问题,顺藤摸瓜总算找到了原因所在,在此记录一下也分享给遇到相同问题的朋友参考。

    (1)项目背景:PC软件需要发送UDP广播包搜索与PC连接的指定设备,然后开启线程循环等待设备回复

    (2)现象:PC软件发送UDP广播包后,并没有收到设备的回复

    (3)原因排查及定位:

      经过排查跟本地的虚拟网卡有关,将所有虚拟网卡和其他网卡禁用以后就能收到设备的回复了

      通过wireshark进一步抓包发现,在开启虚拟网卡时广播包是通过虚拟网卡发出的,并没有通过与设备连接的那个网卡发送出去,从而导致了广播包有去无回

    找到原因那接下来的事情就好办了,但我们肯定不能要求每个用户都手动去禁用自己电脑上的其他网卡,这非常影响用户体验

    那么最好的解决方案是:遍历本地的所有网卡,从每个网卡都发送广播包出去,以下为代码实现

    // 绑定网卡IP发送广播包
    bool SendBroadcast(char* ip)
    {
        WSADATA wsaData;
        WSAStartup(MAKEWORD(2, 2), &wsaData);    // 初始化SOCKET
        
        SOCKET sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    
        /* 本地端口和地址 */
        SOCKADDR_IN src_addr;
        memset(&src_addr, 0, sizeof(src_addr));
        src_addr.sin_family = AF_INET;    // 指代协议族,在socket编程中只能是AF_INET
        src_addr.sin_port = 0;    // 为0表示由系统自动分配端口
        src_addr.sin_addr.s_addr = inet_addr(ip);
    
        int ret = bind(sockfd, (SOCKADDR *)&src_addr, sizeof(SOCKADDR));
        if (SOCKET_ERROR == ret) {    // 成功返回0,失败返回-1
            return false;
        }
    
        bool opt = true;
        ret = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (char*)&opt, sizeof(opt)); // 设置套接字
        if (SOCKET_ERROR == ret) {    // 成功返回0,失败返回-1
            return false;
        }
    
        /* 目的端口和地址 */
        SOCKADDR_IN dst_addr;
        memset(&dst_addr, 0, sizeof(dst_addr));
        dst_addr.sin_family = AF_INET;
        dst_addr.sin_port = htons(5555);
        dst_addr.sin_addr.s_addr = INADDR_BROADCAST;    // 广播地址
        
        unsigned int buf[16] = { 0 };
        buf[0] = 0x12345678;
        buf[1] = 0x87654321;
    
        ret = sendto(sockfd, (char*)buf, 64, 0, (sockaddr*)&dst_addr, sizeof(dst_addr));
        if (SOCKET_ERROR == ret) {    // 成功返回发送的字节数,失败返回-1
            return false;
        }
    
        return true;
    }
    
    int main()
    {
        PIP_ADAPTER_INFO pAdapterInfo = NULL;
        ULONG ulSizeAdapterInfo = 0;
        DWORD dwStatus;
    
        dwStatus = GetAdaptersInfo(pAdapterInfo, &ulSizeAdapterInfo);
        if (dwStatus == ERROR_BUFFER_OVERFLOW) {
            if (!(pAdapterInfo = (PIP_ADAPTER_INFO)malloc(ulSizeAdapterInfo)))
                return;
            dwStatus = GetAdaptersInfo(pAdapterInfo, &ulSizeAdapterInfo);
        }
    
        if (dwStatus != ERROR_SUCCESS)
            return;
    
        while (pAdapterInfo)
        {
            PIP_ADDR_STRING ipList = &pAdapterInfo->IpAddressList;
            while (ipList)  // 一个网卡可能有多个IP地址
            {
                SendBroadcast(ipList->IpAddress.String);
                ipList = ipList->Next;
            }
    pAdapterInfo
    = pAdapterInfo->Next; } return 0; }
  • 相关阅读:
    Ubuntu软件工具推荐
    利用Github Actions自动同步博客园最新内容到GitHub首页
    vscode 使用zsh powerline主题乱码解决方案
    搜索插入位置
    判断二分图
    ~~并发编程(十三):信号量,Event,定时器~~
    ~~并发编程(十二):死锁和递归锁~~
    ~~并发编程(十一):GIL全局解释锁~~
    ~~并发编程(十):线程方法~~
    ~~并发编程(九):多线程与多进程~~
  • 原文地址:https://www.cnblogs.com/IAMSailorMoon/p/15039278.html
Copyright © 2011-2022 走看看