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; }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM