在 .NET有兩種類別可用於建立UDP Socket,一是Socket類別,第二個則是由Socket類別所衍生的UdpClient類別。因為同步比非同步簡單、衍生類別比基底類別簡單、UDP比TCP簡單,所以我把同步的UdpClient當成Socket程式入門的首篇實作文章。
在 .NET有兩種類別可用於建立UDP Socket,一是Socket類別,第二個則是由Socket類別所衍生的UdpClient類別。因為同步比非同步簡單、衍生類別比基底類別簡單、UDP比TCP簡單,所以我把同步的UdpClient當成Socket程式入門的首篇實作文章。
先來談談UDP的特性好了,以下是UDP與TCP一份簡單的比較表:
| UDP | TCP | |
| Socket Type﹝註﹞ | Dgram | Stream | 
| 可靠性 | 較低 | 較高 | 
| 速度 | 較快 | 較慢 | 
| 需連結後通訊 | No | Yes | 
| 點對點通訊 | Yes | Yes | 
| 多點通訊 | Yes | No | 
| 廣播通訊 | Yes | No | 
﹝註﹞關於Socket Type可以參考MSDN文件庫[SocketType 列舉型別]
不可免俗地,還是要來簡單談談建構函式,我把六個建構函式分為四類,如下表:
| 1 | 自動給本機Port號 | UdpClient ()  UdpClient(AddressFamily)  | 
| 2 | 指定本機Port號 | UdpClient(Int32)  UdpClient(Int32, AddressFamily)  | 
| 3 | 依IPEndPoint決定本機Port號 | UdpClient(IPEndPoint) | 
| 4 | 指定遠端主機Hostname與Port號 | UdpClient(String, Int32) | 
﹝註﹞現在都以IPv4的討論為主
第一類的建構函式很適合用於撰寫純Client端時使用,因為此時我們不用管是從哪個Port發出封包,系統自己會幫我們決定好可用的Port。 
第二類的建構函式適用於撰寫UDP的Server端程式,試想如果用系統自由發揮的方法,那Client怎會知道要連到哪個Port呢? 
第三類很有意思的是它綜合了前兩類的用法,原因在於宣告IPEndPoint執行個體時,可以宣告為固定或非固定: 
    (3-1)固定IP與Port:Dim myIPEndpoint As New IPEndPoint(IPAddress.Parse("192.168.11.3"), 6666) 
    (3-2)固定IP,但Port由系統決定:Dim myIPEndpoint As New IPEndPoint(IPAddress.Parse("192.168.11.3"), 0) 
    (3-3)固定Port,用所有可用IP:Dim myIPEndpoint As New IPEndPoint(IPAddress.Any, 6666) 
    (3-4)用所有可用IP且Port由系統決定: Dim myIPEndpoint As New IPEndPoint(IPAddress.Any, 0) 
第四類事實上是宣告一個第一類的UDPClient再加上UDPClient.Connect方法連結到指定主機,千萬不要和前三類弄混了,以為這也是指定本機,這一點千萬要記住。
       講了這麼多,當然要舉個實例來用用,首先是建立一個可以當Server端的UDP程式,在這個程式中會使用BackgroundWorker類別來處理執行緒的問題,如果你對這個類別不熟可以參考之前的文章﹝
多執行緒初探--使用BackgroundWorker(1) 與 多執行緒初探--使用BackgroundWorker(2)   ﹞。為何要使用多執行緒呢?因為這種程式多半會用到無窮迴圈,讓這種玩意兒在主執行緒繞來繞去實在不是一件好主意。一般其實個人是常用Thread 或是 ThreadPool來做,不過因為這兩樣我還沒貼文,所以先用BackgroundWorker來當做示範。畫面上的控制項非常簡單,使用Button控制啟動或停止,NumericUpDown設定UDPclient的Port;至於DataGridView則是當收到訊號後將對方的IP、Port與資料顯示出來。
Server端程式的主要步驟如下 :
步驟一:先宣告一個自訂類別 CSState,這個類別的執行個體將會用來在各事件中傳來傳去。 
   Private Class CSState 
        Public RemoteIpEndPoint As IPEndPoint 
        Public myUDPClient As UdpClient 
        Public ReceiveBytes() As Byte 
    End Class
步驟二:宣告一個DataTable來做為資料的儲存 
    Private myDatatable As New DataTable
步驟三:在Button1.Click事件中產生UdpClient執行個體,並呼叫 BackgroundWorker.RunWorkerAsync方法進入接收資料狀態。 
    If BackgroundWorker1.IsBusy = True Then 
         MessageBox.Show("Socket已啟動") 
    Else 
         Dim iPort As Integer 
         iPort = NumericUpDown1.Value 
         Dim myObj As New CSState 
         myObj.myUDPClient = New UdpClient(iPort) 
         myObj.RemoteIpEndPoint = New IPEndPoint(IPAddress.Any, 0) <==這是Server接收的一個重點,要用(IPAddress.Any, 0)的原因在於Server端程式一開始無法預測會是哪個IP從哪個Port傳給它﹝除非有其它原因要鎖住來源﹞。 
         BackgroundWorker1.RunWorkerAsync(myObj) 
         Label2.ForeColor = Color.Blue 
         Label2.Text = "UDP運作中" 
     End If
 步驟四:在BackgroundWorker1.DoWork事件中撰寫接收資料的程序,並於收到資料後呼叫BackgroundWorker1.ReportProgress以處理畫面展現。 
    Dim myObj As CSState = CType(e.Argument, CSState) 
     While True 
         Try 
           myObj.ReceiveBytes = myObj.myUDPClient.Receive(myObj.RemoteIpEndPoint) 
             BackgroundWorker1.ReportProgress(0, myObj) 
             If BackgroundWorker1.CancellationPending = True Then 
                 myObj.myUDPClient.Close() 
                 Exit While 
             End If 
         Catch ex As Exception 
             MessageBox.Show(ex.ToString) 
         End Try 
     End While
步驟五:在BackgroundWorker1.ProgressChanged事件中處理DataTable的資料,使其能展現於DataGridView上 
       Dim myObj As CSState = CType(e.UserState, CSState) 
       Dim xRow As DataRow = myDatatable.NewRow() 
       xRow.Item(0) = myObj.RemoteIpEndPoint.Address.ToString() 
       xRow.Item(1) = myObj.RemoteIpEndPoint.Port.ToString() 
       xRow.Item(2) = Encoding.GetEncoding(950).GetString(myObj.ReceiveBytes) 
       myDatatable.Rows.Add(xRow)
以上Server端的完整程式碼可以在此下載[VB2005]:SyncUDPClient_1.rar
至於Client端﹝表單畫面如上圖﹞的程式就更簡單了, 只有以下短短幾行,這邊使用UdpClient.Send (Byte[], Int32, IPEndPoint) 多載方法來傳送資料
   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 
       Dim myUDPClient As New UdpClient() 
       Dim ServerIpAddress As IPAddress 
       Try 
           ServerIPaddress = IPAddress.Parse(TextBox1.Text) 
       Catch ex As Exception 
           MessageBox.Show("Server IP設定錯誤") 
           Exit Sub 
       End Try 
       Dim iPort As Integer 
       iPort = NumericUpDown1.Value 
       Dim RemoteIpEndPoint As New IPEndPoint(ServerIPaddress, iPort) 
       Dim myBytes As Byte() 
       myBytes = Encoding.GetEncoding(950).GetBytes(Trim(TextBox2.Text)) 
       If myBytes.Length > 0 Then 
           myUDPClient.Send(myBytes, myBytes.Length, RemoteIpEndPoint) 
       Else 
           MessageBox.Show("無資料可傳送!!") 
       End If 
   End Sub
以上Client端的完整程式碼可以在此下載[VB2005]:SyncUDPClient_2.rar
UdpClient就是這麼容易上手,其實只要把上面兩個程式融會貫通,稍微變化一下,就可以寫成一個兩端互相通信的小應用程式,各位有興趣可以自行測試看看,有任何指教也煩請不吝留言。