Working with sockets in Windows 8 store applications

Posted: (EET/GMT+2)

 

TCP and UDP communication is universal, and highly valuable in many situations, especially when communicating with devices and enterprise systems. Although modern thinking is bound to do everything through HTTP, this isn't always the best option, or sometimes not even possible.

Now, in the .NET world, for instance TCP communication has been done with classes such as TCPClient and TCPListener. I've used these classes many times myself, but moving to the world of Windows 8 store application development (aka "Modern UI" or "Metro") requires learning something new: the old trusty .NET classes aren't available anymore.

Enter a new class called StreamSocket. This class works similar to the TCPClient and TCPListener classes in traditional .NET, but as you can guess, code needs more changes than just replacing the classes being used.

To get you started, here's a very quick code sample:

using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
...

// connect to server at port 8000
StreamSocket client = new StreamSocket();
HostName host = new HostName("my.server.somewhere");
await client.ConnectAsync(host, "8000");

// read the first text line from the server (think SMTP or POP3, for instance)
DataReader reader = new DataReader(client.InputStream);
reader.InputStreamOptions = InputStreamOptions.Partial;

string greeting = await reader.ReadLine();

Now, the last line contains a call to the ReadLine method. This doesn't exist by default in the DataReader class, but can be easily extended with an extension method. For instance:

using System.Threading.Tasks;
using Windows.Storage.Streams;
...

namespace MyStoreAppNamespace
{
    internal static class HelperMethods
    {
        internal static async Task ReadLine(this DataReader stream)
        {
            // start reading data from the socket until a CRLF is found
            MemoryStream buffer = new MemoryStream();
            int bytesRead = 0;
            while (true)
            {
                // check to see if any data is available for reading
                int valueRead = 0;
                int retryCount = 3;
                while (retryCount > 0)
                {
                    try
                    {
                        if (retryCount < 3) await Task.Delay(1000);
                        await stream.LoadAsync(1);
                        valueRead = stream.ReadByte();
                        break;
                    }
                    catch (Exception)
                    {
                        retryCount--;
                    }
                }

                // were we able to read anything?
                if (retryCount <= 0) break;

                byte readByte = (byte)valueRead;
                // check for line feed character (CRLF = ASCII 13, 10)
                if (readByte == 10) break;

                buffer.WriteByte(readByte);
                bytesRead++;
            }

            // convert the buffer to a string
            if (bytesRead == 0) return "";
            else
            {
                string line = Encoding.UTF8.GetString(buffer.ToArray(), 0, bytesRead);
                // remove extra CR character (if any)
                if (line.EndsWith("\r")) {
                    line = line.Substring(0,line.Length-1);
                }
                return line;
            }
        }

    }
}

With this code, you should get started pretty quickly.

Enjoy!