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; }
posted on 2021-07-21 14:18  Cynthia_W  阅读(2596)  评论(0编辑  收藏  举报