在Win7/Win8下傳送UDP廣播封包

在撰寫UDP的應用軟體時,有時候會遇到需要發送廣播封包的需求,而這種情況下,就會選擇使用UDP的方式來傳送,而最簡單的方式就是使用UdpClient來處理了;例如說在不知道對方的IP位置的情況,而對方有做類似IpSearch的功能時,就可以利用廣播的方式讓對方將自己目前的IP位置給傳送回來。

廣播封包的發送通常來說動作就是向255.255.255.255這個廣播位置去做資料的發送,然後再去讀取回送的資料,而本篇筆記主要是在Windows XP跟之後的作業系統(Windows7/WIndows8)之間的差異性

筆者在早期有撰寫了一個簡單的小軟體,來做廣播處理的動作,在發送UDP封包的部分,程式碼大致如下
        Dim bEP As New IPEndPoint(IPAddress.Broadcast, 4550)
        Client = New UdpClient(4550, AddressFamily.InterNetwork)
        Client.EnableBroadcast = True
        Client.Send(btySend, btySend.Length, "255.255.255.255", 4550)
        Threading.Thread.Sleep(CInt(txtDelay.Text))
        Do
            If Client.Available > 0 Then
                btyRecv = Client.Receive(bEP)
                If btyRecv IsNot Nothing AndAlso btyRecv.Length > 0 Then
                    ''處理接收到資料後的事情
                End If
            Else
                Exit Do
            End If
        Loop
        Client.Client.Close()

在Windows XP上面一切相安無事,也能正常地從遠端抓到回傳的資料;但到了Windows 7之後,怪怪,不論如何都沒有辦法取回遠端的回應,而利用Wireshark之類的封包監控軟體去查看網路的傳送狀況,X! 任何東西都沒有送出來,開VM跑XP,同樣的程式又可以運作正常,這是啥狀況 Orz Orz

這個狀況一開始實在摸不著頭緒,直到今天想說再搜尋一下資料,總算理出一些端倪;解決方式的源頭來自下面這篇討論
http://stackoverflow.com/questions/6290329/why-is-my-udp-broadcast-failing
其中有一段提到
『Windows 7 handles 255.255.255.255 broadcast in a different way』
往下追之後才驚覺原來是作業系統對於廣播位址的處理不同了,而在Windows7/Windows8要綁定一個IP地址之後才能正常的發送以及接收了,有了這個線索之後,轉而利用socket來處理,並且修改相關程式碼如下
        Dim bEP As New IPEndPoint(IPAddress.Any, 4550)
        Dim s As New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
 
        Dim host As IPHostEntry
        host = Dns.GetHostEntry(Dns.GetHostName)
        For Each IP As IPAddress In host.AddressList
            If (IP.AddressFamily = AddressFamily.InterNetwork) Then
                s.Bind(New IPEndPoint(IP, 4550))
                Exit For
            End If
        Next
 
        s.EnableBroadcast = True
        s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, True)
        s.SendTo(btySend, New IPEndPoint(IPAddress.Broadcast, 4550))
 
        For i As Integer = 0 To 30
            Threading.Thread.Sleep(100)
            Application.DoEvents()
        Next
 
        ReDim btyRecv(1024)
 
        Do
            If s.Available > 0 Then
                Dim aa As Integer = s.ReceiveFrom(btyRecv, bEP)
                If btyRecv IsNot Nothing AndAlso aa >= 76 Then
                    ''處理接收到資料後的事情

                End If
            Else
                Exit Do
            End If
        Loop
        s.Close()
        s = Nothing

改用這個方式總算能夠正常的在Windows 8的作業系統上正常的傳送以及接收UDP的廣播封包了;拖了好長時間,總算能夠宣布破案! 相關動作特別筆記一下,以免年紀大了失憶情況嚴重 XD

留言

這個網誌中的熱門文章

開啟cshtml檔案時,出現『並未將物件參考設定為物件執行個體』的錯誤訊息

無法設定中斷點 尚未載入符號檔

DataGridView欄位計算總合