UDP and Windows 8 apps
The Windows 8 app I’m currently working on requires me to send some data over a wireless network using UDP. This is usually done by using the Socket class contained in the System.Net.Sockets namespace. However, this isn’t supported in Windows RT, which replaces the behavior of Socket with several equivalent classes. The class used for UDP is DatagramSocket. While the code using DatagramSocket is relatively short and simple, there are some intricacies involved in getting it to function properly, so in this post I’ll make things simpler by providing a working example.
At a conceptual level, the steps required to open a UDP connection and send data are very simple:
1. Create a local socket.
2. Connect to a remote host.
3. Send data to the remote host.
The code itself is short, so let’s break it down line-by-line. Bonus points if you can guess what I’m working on from the IP address and port numbers!
Creating the local socket
The first step is creating the socket, in this case a DatagramSocket:
DatagramSocket udpSocket = new DatagramSocket();
One advantage of DatagramSocket is that I don’t have to specify what kind of protocol I want to use, because it sends exclusively UDP packets.
Next I need to bind the socket to a local port, which specifies which port you want the UDP packets to originate from. This is done by calling the DatagramSocket.BindServiceNameAsync() method. In my case, I’ll be using the port number 5556:
await udpSocket.BindServiceNameAsync(“5556”);
It’s as simple as passing a string containing the port number. I use the await keyword here because BindServiceNameAsync() is an asynchronous method. For more documentation on the await keyword and Windows RT Tasks, check the resources at the end of the article.
Connecting to a remote host
The second step is to open a connection to a remote host. In this example I want to connect to the IP address 192.168.1.1, but the DatagramSocket.ConnectAsync() method takes an instance of the HostName class as an argument. So first I need to create a new HostName to represent the remote host:
HostName remoteHost = new HostName(“192.168.1.1”);
Again, the argument I’m passing is a string containing the IP address or URL I want to connect to. I can then open the connection by calling ConnectAsync and passing the HostName I just created and the port I want to send data to on the remote host:
await udpSocket.ConnectAsync(remoteHost, “5556”);
Sending data to the remote host
Once the connection is established, it’s time to send data. The DatagramSocket class doesn’t contain any methods for sending packets, so I need to use the aptly-named DataWriter class. The first step of sending data is to create a new DataWriter, passing it the OutputStream property of my DatagramSocket, udpSocket:
DataWriter udpWriter = new DataWriter(udpSocket.OutputStream);
Now, say I want to send the string “juncti juvant” to the remote host. DataWriter doesn’t have any single method to handle this operation; sending data is a two part process. First I need to write the data to the OutputStream:
udpWriter.WriteString(“juncti juvant”);
Check out the documentation on the DataWriter class to see what other kinds of data you can write.
The data isn’t heading to the remote host yet; now I need to actually make the DataWriter send a UDP packet. To do this I call the DataWriter.StoreAsync() method:
await udpWriter.StoreAsync();
And with that, a UDP packet containing the payload “juncti juvant” is on its way to the remote host!
My combined code to send a UDP packet consists of the following:
// Create a new socket and bind it to a local port DatagramSocket udpSocket = new DatagramSocket(); await udpSocket.BindServiceNameAsync(“5556”); // Open a connection to a remote host HostName remoteHost = new HostName(“192.168.1.1”); await udpSocket.ConnectAsync(remoteHost, “5556”); // Send a data string to the remote host in a UDP packet DataWriter udpWriter = new DataWriter(udpSocket.OutputStream); udpWriter.WriteString(“juncti juvant”); await udpWriter.StoreAsync();
Resources
DatagramSocket: https://msdn.microsoft.com/en-us/library/windows/apps/windows.networking.sockets.datagramsocket.aspx
HostName: https://msdn.microsoft.com/en-us/library/windows/apps/windows.networking.hostname.aspx
DataWriter: https://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.streams.datawriter.aspx
await keyword and Tasks: https://msdn.microsoft.com/en-us/library/hh156528.aspx
Comments
Anonymous
September 12, 2012
Just to make sure I understand, is this class available from the Windows RT environment?Anonymous
September 13, 2012
Yes, it's available in the RT environment!Anonymous
January 15, 2013
How do know what exceptions could be thrown, for example if the address were in use when: BindServiceNameAsync()Anonymous
January 23, 2013
As far as I know, that information isn't listed in any central place. The code example at the bottom of the following link will give you an idea of how to deal with that method throwing exceptions msdn.microsoft.com/.../jj635238.aspx