In UDP, no connection needs to be created. As a result, there's no differentiation between client and server, and no listener class. Data can be sent immediately once the UdpClient object is created. However, you cannot use the NetworkStream to send messages with UDP. Instead, you must write binary data directly using the Send() and Receive() methods of the UdpClient class. Every time you use the Send() method, you specify three parameters: a byte array, the length of the byte array, and the IPEndPoint for the remote computer where the message will be sent.
The following example rewrites the earlier TCP demonstration to use UDP. Because UDP does not make any distinction between client and server, we only need one application: a generic client that can both send and receive messages. When the console application is started, it prompts you for the IP address and remote port where messages should be sent, and the local port that will be polled for incoming messages. Here's the complete code:
Imports System.Net Imports System.Net.Sockets Imports System.IO Imports System.Threading Imports System.Text Module UdpClientConsole ' The port used to listen for incoming messages. Private LocalPort As Integer Public Sub Main() ' Set up ports. Console.Write("Remote IP: ") Dim IP As String = Console.ReadLine() Console.Write("Remote port: ") Dim Port As String = Console.ReadLine() ' Define the IP and port where messages are sent. Dim RemoteEndPoint As New IPEndPoint(IPAddress.Parse(IP), _ Int32.Parse(Port)) Console.Write("Local port: ") LocalPort = Int32.Parse(Console.ReadLine()) Console.WriteLine(New String("-", 40)) Console.WriteLine() ' Create a new thread for receiving incoming messages. Dim ReceiveThread As New Thread(AddressOf ReceiveData) ReceiveThread.IsBackground = True ReceiveThread.Start() Dim Client As New UdpClient() Try ' Loop until the word QUIT is entered. Dim Text As String Dim Data() As Byte Do Text = Console.ReadLine() ' Send the text to the remote client. If Text <> "QUIT" Then ' Encode the data to binary manually using UTF8 encoding. Data = Encoding.UTF8.GetBytes(Text) ' Send the text to the remote client. Client.Send(Data, Data.Length, RemoteEndPoint) End If Loop Until Text = "QUIT" Catch Err As Exception Console.WriteLine(Err.ToString()) End Try End Sub Private Sub ReceiveData() Dim Client As New UdpClient(LocalPort) Dim Data() As Byte Dim Text As String Do Try ' Receive bytes. Data = Client.Receive(Nothing) ' Try to convert bytes into a message using UTF8 encoding. Text = Encoding.UTF8.GetString(Data) ' Display the retrieved text. Console.WriteLine("*** RECEIVED: " & Text) Catch Err As Exception Console.WriteLine(Err.ToString()) End Try Loop End Sub End Module
Note that the code passes a null reference (Nothing) to the UdpClient.Receive() method. This instructs it to retrieve any message that has been received on the listening port. Alternatively, you could supply an IPEndPoint representing a remote client. In this case, the Receive() method would only retrieve data sent by that client.
If you start two instances of the UDP test application, you might have an exchange such as the one shown in Figure 7-6. In this example, both instances are on the local computer. They differ only in the port that they're using.
UDP provides one feature that TCP doesn't: the ability to send broadcasts and multicasts.
Broadcasts are network messages that are sent to all devices on the local subnet. When a client receives a broadcast, it decides whether the message is of interest or should be discarded. The architecture of broadcast messages makes them quite bandwidth-intensive, because a separate copy of the message is sent to each device. For this reason, routers always block broadcast messages, and they can never reach outside their own portion of the network.
To send a broadcast message, you use an IP address that identifies the network and has all host bits set to 1. In other words, if the network is identified by the first three bytes (142.128.0), you would send a broadcast to all machines on this network by sending a UDP message to the IP address (126.96.36.199). Even without knowing the network portion of an IP address, you can set all bits to 1, and use the broadcast address 255.255.255.255, which will attempt to contact every reachable computer (but, once again, it will be blocked by all routers).
Here's a snippet of code for use in sending a simple broadcast message:
Dim IP As String = "255.255.255.255" Dim Port As String = 8800 Dim RemoteEndPoint As New IPEndPoint(IPAddress.Parse(IP), _ Int32.Parse(Port)) Dim Client As New UdpClient() Dim Data() As Byte = System.Text.Encoding.UTF8.GetBytes("Broadcast Message") ' Send the broadcast message. Client.Send(Data, Data.Length, RemoteEndPoint)
Broadcasting would be highly inefficient if it were implemented with TCP, because the broadcaster would be flooded with acknowledgment messages from every recipient. As it is, broadcast messages with UDP still aren't that bandwidth-friendly. A much more efficient protocol is multicasting. Multicasting provides a way to define "groups" of computers with a multicasting IP address. Devices can join this group, in which case they'll receive all multicast messages, or leave it at will. Even better, multicast messages can cross router boundaries and flow freely across the Internet. Unfortunately, multicasting still isn't supported by all network hardware.
Multicast addresses range from 188.8.131.52 to 184.108.40.206. However, not all of these addresses are available (some have special meanings, and others are scope-relative, which means they cannot cross a router). You can register a multicast port for your application from the IANA, which is responsible for assigning all multicast ports. See http://www.iana.org/assignments/multicast-addresses for current assignments. Alternatively, you can use the predefined multicast address 220.127.116.11 to access all computers on a subnet. (You can also use a machine and device capabilities (MADCAP) server to request a dynamically assigned multicast address that will be used for a limited period of time, although this technique is beyond the scope of this book.)
Dim IP As String = "18.104.22.168" Dim Port As String = 8800 Dim RemoteEndPoint As New IPEndPoint(IPAddress.Parse(IP), _ Int32.Parse(Port)) Dim Client As New UdpClient() Dim Data() As Byte = System.Text.Encoding.UTF8.GetBytes("Multicast Message") ' Send the broadcast message. Client.Send(Data, Data.Length, RemoteEndPoint)
In .NET, a client can join a multicast group using the UdpClient.JoinMulticastGroup() method, and unsubscribe using the DropMultiCastGroup() method. Thus, before you can receive the multicast message shown earlier, you would need to use this code:
Dim Client As New UdpClient(LocalPort) Client.JoinMulticastGroup(IPAddress.Parse("22.214.171.124"))
Both broadcasting and multicasting could be used to support peer-to-peer discovery, although they have several weaknesses. Broadcasting is bandwidth-intensive, and can't propagate beyond a local network. Multicasting is much more efficient, but isn't supported by all ISPs.