Welcome to the last part of this series in which we have been exploring how Windows 8 applications can connect with all kinds of services. We have explored quite a few ways to allow Windows 8 apps to get data, including ASMX, WCF, REST, RSS and many more. Also, we have looked at how we can allow apps to update live tiles through push notifications.
The constant between all these is that we have control over the protocol used on the server-side. If this isn’t the case, we are stuck with all these supported protocols. What if we for example want to build an app that integrates with an Exchange server? We can’t simply re-write Exchange (I think it would be quite complex to say the least) so we don’t have any ways to interact with it using for example WCF.
In this article, we’ll explore the use of sockets. They are the solution to connect to other types of services that don’t belong in the categories we have already explored.
The code for this article can be downloaded here.
Sockets in Windows 8
In Windows 8 apps, we have the ability to perform communication using sockets. There are several types of sockets supported: TCP, UDP and web sockets. The support to communicate with these services is based on classes that are located in the Windows.Networking.Sockets namespace.
A good question might be: when do I need to look into socket communication? A very valid question, since sockets are often avoided by most developers because of their complexity. The answer to that question lies in the fact that we don’t always have the option to write the service endpoint ourselves. Sometimes, we need to connect with an existing service layer (as mentioned in the intro, for example Exchange). If we want to build an app that needs to integrate with Exchange for example, sockets are probably the only way we can connect with the server-side (Exchange offers something called EWS aka Exchange Web Services which could also be used here). So to conclude, sockets should be the option to look into when you need to connect with a service layer that uses a protocol that isn’t directly supported by any of the other networking technologies we’ve looked at in this series. It’s certainly not a replacement for WCF or REST communication: when these types of endpoints are exposed, by all means, use them with the appropriate client-side code!
The following classes are supported in Windows 8’s API to communicate with sockets:
- StreamSocket: the default class we’ll use to communicate with a socket using TCP
- StreamSocketListener: the class we’ll be using in an app that needs to listen for incoming TCP connections
- DatagramSocket: this class is used for communication using a UDP datagram socket. We won’t be exploring this class in this article
- MessageWebSocket: allows us to read and write messages with a web socket
- StreamWebSocket: allows us to read and write streams with a web socket
Let’s take a look at how we can work with sockets. We’ll start with the most typical one, the TCP socket. As mentioned before, we’ll be using the StreamSocket and the StreamSocketListeren for this app.
Communicating using TCP sockets
When we want to build an app that uses TCP sockets, we can do 2 things: connecting and sending data to a socket or listening for an incoming connection and reading out the data. To perform these 2 tasks, we can use the StreamSocket and the StreamSocketListener classes.
Let’s build an app that uses both classes and therefore communicates with itself. Of course, you can use the same code to connect with any other socket. Create a new app and name it MySocketApp.
The UI for the application is quite simple as can be seen below. The XAML for this UI can be found in the sample download.
First, we’ll create a socket listener (StreamSocketListener). On this, we can listen for a connection. When a connection is made from an outside socket, the code in the callback will be called.
private StreamSocketListener listener;
private async void CreateSocketListenerButton_Click_1(object sender, RoutedEventArgs e)
{
listener = new StreamSocketListener();
listener.ConnectionReceived += listener_ConnectionReceived;
}
The listener now needs to be bound to a local address. This is the address the listener will be monitoring for incoming connections.
try
{
await listener.BindServiceNameAsync(AddressListenerTextBox.Text);
SocketListenerStatusTextBlock.Text = "I'm listening...";
}
catch (Exception exception)
{
SocketListenerStatusTextBlock.Text = "Something went wrong: " + exception.Message;
}
In the callback, listener_ConnectionReceived, we need to specify what needs to happen when a connection is coming in. When the connection is made, we can read out the message from the stream. The latter can be done using a DataReader which we pass the InputStream of the connecting socket.
async void listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
DataReader reader = new DataReader(args.Socket.InputStream);
try
{
while (true)
{
uint sizeFieldCount = await reader.LoadAsync(sizeof(uint));
if (sizeFieldCount != sizeof(uint))
{
return;
}
uint stringLength = reader.ReadUInt32();
uint actualStringLength = await reader.LoadAsync(stringLength);
if (stringLength != actualStringLength)
{
return;
}
Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => SocketListenerStatusTextBlock.Text = "Received: " + reader.ReadString(actualStringLength));
}
}
catch (Exception exception)
{
Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => SocketListenerStatusTextBlock.Text = "Something went wrong");
}
}
Note that this code is executing on a background thread. Therefore, when we want to update the UI, we can’t do that directly, we need to use the Dispatcher.RunAsync. This allows us to pass code to the Dispatcher which is associated with the main UI thread. From there, we can update the UI.
Let’s now look at the creation of the socket. This will be the socket that will be sending the data later on. Of course, we need to know where we are going to send the data to, so we need to pass the same address as where the StreamSocketListener is listening on.
private StreamSocket socket;
private async void CreateSocketButton_Click_1(object sender, RoutedEventArgs e)
{
try
{
hostName = new HostName(AddressTextBox.Text);
}
catch (ArgumentException argex)
{
SocketStatusTextBlock.Text = "Error: Invalid host name.";
return;
}
socket = new StreamSocket();
}
Next, we can connect with the listener using the ConnectAsync method as follows.
try
{
await socket.ConnectAsync(hostName, ServiceNameTextBox.Text);
SocketStatusTextBlock.Text = "Connected";
}
catch (Exception exception)
{
SocketStatusTextBlock.Text = "Something went wrong: " + exception.Message;
}
With the StreamSocketListener listening for an incoming message and the socket connected, we can now send data. Sending data is done by creating a DataWriter, which gets associated with the OutputStream of the StreamSocket.
private async void SendDataButton_Click_1(object sender, RoutedEventArgs e)
{
DataWriter writer = new DataWriter(socket.OutputStream);
string stringToSend = "Hello SilverlightShow";
writer.WriteUInt32(writer.MeasureString(stringToSend));
writer.WriteString(stringToSend);
}
At this point, we haven’t send the data yet. We can do that using the StoreAsync method as follows:
try
{
await writer.StoreAsync();
}
catch (Exception exception)
{
SocketStatusTextBlock.Text = "Something went wrong: " + exception.Message;
}
If all goes well, we can send data and the application should display the received data in the listener block on the left.
Let’s now look at how we can work with a WebSocket in a next sample.
Communicating with web sockets
In the Windows.Networking.Sockets namespace, there’s also a number of classes that allow working with web sockets. The WebSocket protocol allows 2-way communication in a fast and secure way between client and server over the web. This means that both ends of the connection can receive and send messages in real time. Stock apps, games and other apps that require fast data transfer are an ideal candidate for using web sockets.
Creating a web socket connection between client and server is done by first creating an HTTP-based handshake, which if successful, will be upgraded to web sockets, on top of the TCP connection. From then on, the data is transferred directly using the WebSocket protocol and no longer over HTTP.
In WinRT, there are two classes: MessageWebSocket and StreamWebSocket. The first is for smaller messages, the latter supports larger messages in binary format.
In the following sample, we are going to use an existing web socket, available from ws://echo.websocket.org. This is an echo service, it will send back the same information that you send it. It suffices for our application here. Start by creating a new app and name it WebSocketApp.
The UI is again pretty straightforward as you can see below.
When we click on the Send Message button, we want to send a message to the web socket and receive its response. We first instantiate the MessageWebSocket and then register for both the MessageReceived and Closed events.
private async void SendMessageButton_Click_1(object sender, RoutedEventArgs e)
{
try
{
Uri webSocketUri = new Uri(AddressTextBox.Text.Trim());
messageWebSocket = new MessageWebSocket();
messageWebSocket.Control.MessageType = SocketMessageType.Utf8;
messageWebSocket.MessageReceived += webSocket_MessageReceived;
messageWebSocket.Closed += webSocket_Closed;
}
...
}
The next step is connecting with the web socket. This can be done using the ConnectAsync method, passing in the URI we want to connect with.
await messageWebSocket.ConnectAsync(webSocketUri);
Next, we create a DataWriter, passing in the OutputStream of the socket (similar to what we had with the StreamSocket!).
dataWriter = new DataWriter(messageWebSocket.OutputStream);
StatusTextBlock.Text = "Connected";
We can now write a message in the stream.
dataWriter.WriteString(MessageTextBox.Text);
await dataWriter.StoreAsync();
StatusTextBlock.Text = "Sending data";
The web socket in this case will response with the same message (remember, it’s an echo service). Again similar to StreamSockets, we will use a DataReader to read the incoming message.
using (DataReader dataReader = args.GetDataReader())
{
dataReader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
string receivedMessage = dataReader.ReadString(dataReader.UnconsumedBufferLength);
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
StatusTextBlock.Text = "Message received: " + receivedMessage;
});
}
The result can be seen below. We have sent a message and successfully received it back from the web socket!
Summary
In this article, we have worked with sockets, both StreamSockets and WebSockets. Sockets are sometimes the only way to communicate with a service that doesn’t support any of the other types of services we have looked at previously in this articles.
About the author
Gill Cleeren is Microsoft Regional Director (www.theregion.com), Silverlight MVP (former ASP.NET MVP) and Telerik MVP. He lives in Belgium where he works as .NET architect at Ordina (http://www.ordina.be/). Passionate about .NET, he’s always playing with the newest bits. In his role as Regional Director, Gill has given many sessions, webcasts and trainings on new as well as existing technologies, such as Silverlight, ASP.NET and WPF at conferences including TechEd Berlin 2010, TechDays Belgium – Switzerland - Sweden, DevDays NL, NDC Oslo Norway, SQL Server Saturday Switserland, Spring Conference UK, Silverlight Roadshow in Sweden, Telerik RoadShow UK… He’s also the author of many articles in various developer magazines and for SilverlightShow.net and he organizes the yearly Community Day event in Belgium. He also leads Visug (www.visug.be), the largest .NET user group in Belgium. Gill is the author of “Silverlight 4 Data and Services Cookbook”. In 2012, the second edition, “Silverlight 5 Data and Services Cookbook” is released.
You can find his blog at www.snowball.be.
Twitter: @gillcleeren