Windows Phone 7 Mango - BingMapsTask Microsoft Community Contributor Award 2011

Windows Phone 7 Mango - Sockets

Published on Tuesday, May 24, 2011 11:03:00 PM UTC in Programming

Update 2011-09-30: This article is compatible with the final version of Windows Phone 7.1 "Mango".

Socket support is one of the exciting features that will be introduced with the next release of Windows Phone 7. For example, it should enable game developers to create better multiplayer experiences and add the possibility to bring a whole new class of applications to the phone (think chat/IM clients that rely on custom connections and protocols). In this post we'll see how sockets are used on the phone.

Socket and SocketAsyncEventArgs

These are the two core classes used for socket communication. The Socket class obviously is the one that implements the main functionality, including methods for connecting the socket, sending and receiving data as well as shutting down and closing the socket. SocketAsyncEventArgs on the other hand is a representation of an asynchronous socket operation and functions as a container for all sorts of accompanying data. It includes information about the socket operation itself, the buffer (data) to be transferred in send and receive operations and the configuration of the remote endpoint to connect to. The event args class also provides a Completed event that is raised when an operation has finished asynchronously.

Sample

To test the feature, I've created a small server as .NET console application that simply listens for incoming connections and prints whatever messages are sent to the console.

image

The Windows Phone side on the other hand only has a simple UI that allows entering the host address and port as well as the message to send:

image

Socket communication always requires some low-level work and forces you to put some thinking into pesky details; for example, finding a way to determine that a transfer has finished at the receiving end (e.g. by prefixing the transfer with the total message length at the sending end or similar). But this post is not about learning sockets, so I won't go into more theory details. Instead I show how it's done on the phone and invite you to take a look at the included source code for a full sample implementation.

// create endpoint var ipAddress = IPAddress.Parse(host);
var endpoint = new IPEndPoint(ipAddress, port);

// convert text to send (prefix with length) var message = string.Format("{0};{1}", Message.Text.Length, Message.Text);
var buffer = Encoding.UTF8.GetBytes(message);

// create event args var args = new SocketAsyncEventArgs();
args.RemoteEndPoint = endpoint;
args.Completed += SocketAsyncEventArgs_Completed;
args.SetBuffer(buffer, 0, buffer.Length);

First of all I create the event args I mentioned above. The minimum requirement to send a message is to define the endpoint of the receiver (which I create by parsing the string input from the textbox you can see in the screenshot). That endpoint is used as value for the "RemoteEndPoint" property of the event args. The second piece is the actual content I want to send. Since this needs to be a byte array, I use the encoding class to convert the text from the textbox to a binary representation. The last part to note here is that I hook the completed event of the event args, which will be raised once an asynchronous socket operation has finished.

Next I create the socket and start the asynchronous connect method:

// create a new socket var socket = new Socket(AddressFamily.InterNetwork,
    SocketType.Stream,
    ProtocolType.Tcp);

// connect socket bool completesAsynchronously = socket.ConnectAsync(args);

// check if the completed event will be raised. // if not, invoke the handler manually. if (!completesAsynchronously)
{
    SocketAsyncEventArgs_Completed(args.ConnectSocket, args);
}

The last part needs some more explanation: there is a possibility that "ConnectAsync" (although the name already suggests it's async nature) is completed synchronously. This is indicated by the return value. It's important to check that value, because if it is false, the above mentioned Completed event of the event args will never be raised. A common pattern is to invoke the event handler manually if this happens, so the execution flow can continue similarly like in the regular case of asynchronous execution. If you look at the documentation of the Socket class methods you will realize that all the operation methods (sending, receiving, etc.) have this bool return value, which means you have to apply this pattern to every operation you perform on the socket.

private void SocketAsyncEventArgs_Completed(object sender, SocketAsyncEventArgs e)
{
    // check for errors if (e.SocketError != SocketError.Success)
    {
        Dispatcher.BeginInvoke(() => MessageBox.Show("Error during socket operation: " + e.SocketError));

        // do some resource cleanup CleanUp(e);
        return;
    }

    // check what has been executed switch (e.LastOperation)
    {
        case SocketAsyncOperation.Connect:
            HandleConnect(e);
            break;
        case SocketAsyncOperation.Send:
            HandleSend(e);
            break;
    }
}

The event handler for the Completed event demonstrates an important concept: that the involved async event args class really is a unified representation of all possible socket operations. As you can see, I'm checking for the value of the "LastOperation" property here, and delegate execution to dedicated methods that handle the connect and send operation results. By doing that I'm able to reuse the event args I created in the beginning for all following operations I want to perform on the socket. It's is a very common pattern to do that and use a single event handler like above as a central hub for all operations (but of course you're also free to use individual event handlers and create new event args for each step and operation).

The two sample methods that handle the connect and send operations are almost self-explanatory:

private void HandleConnect(SocketAsyncEventArgs e)
{
    if (e.ConnectSocket != null)
    {
        // simply start sending bool completesAsynchronously = e.ConnectSocket.SendAsync(e);

        // check if the completed event will be raised. // if not, invoke the handler manually. if (!completesAsynchronously)
        {
            SocketAsyncEventArgs_Completed(e.ConnectSocket, e);
        }
    }
}

private void HandleSend(SocketAsyncEventArgs e)
{
    // show a notification Dispatcher.BeginInvoke(() => MessageBox.Show("Sending successful!"));

    // free resources CleanUp(e);
}

After the connect, we simply continue by starting the send operation. You may recall that we already filled the data that should be send into the event args in the very beginning, so there's no more preparation to do here. Once again we have to check whether the send operation executed synchronously. In any case we proceed with the central Completed event handler after the sending has finished.

The method that handles the successful sending simply shows a message box and cleans up the resources occupied by the socket. As you can see by the use of the Dispatcher, working with sockets is one of the cases in Silverlight where no automatic marshaling back to the UI thread is performed by the runtime for you. You have to be careful not to perform any invalid cross-threading access and do the manual context switch back to the UI thread if you want to access any UI-related elements.

Cleaning up a socket, as usual, requires a shutdown (to ensure everything is flushed and properly processed), followed by closing the socket.

private void CleanUp(SocketAsyncEventArgs e)
{
    if (e.ConnectSocket != null)
    {
        e.ConnectSocket.Shutdown(SocketShutdown.Both);
        e.ConnectSocket.Close();
    }
}

The following again shows the unified flow and processing schema for all available operations (connect, different send and receive variants) made possible by using the same event args for all of them.

image

Summary

Even though it's often complex to work with and requires some work to master, I think a lot of people will be pleased by the fact that socket communication will be included in the Mango update. Feel free to download the following source code for a small sample of Windows Phone 7 communicating with a .NET sockets server. Remember to start both the server and Windows Phone 7 client project as well as enter the correct server IP address for the sample to work.

Download sample source code

Tags: Mango · Silverlight · Windows Phone 7