Random geekery since 2005.

Husband, father, programmer, speaker, writer, blogger, podcaster, collector, traveler, golfer.

31 Days of Mango | Day #21: Sockets

Written in

by

Day21-SocketsDay20-RingtonesDay19-AddingTiltEffectsDay18-ExpressionBlendSampleDataDay17-WindowsAzure

This article is Day #21 in a series called 31 Days of Mango, and was written by guest author Parag Joshi.  Parag can be reached on Twitter at @ilovethexbox.

Today we will take a peek at the new support for sockets announced in Windows Phone 7.1. So, what are sockets? Simply put it is the communication mechanism based on TCP/IP that is used for remote applications like printing, video conferencing and many more.

Before we delve into how to write a socket based windows phone application let us take time to understand what sockets is all about.

Sockets – What is involved?

Applications communicate via sockets based on a socket address. A socket address is a combination of a TCP/IP address and a port. Using this information, applications can communicate with each other over a local network or via the internet.

The article mentioned below gives a very good explanation of the terms and technology behind sockets. As a programmer, all you need to know is how to connect (if using TCP/IP) and how to send / receive data.

Sockets is a low level technology. This means that you need to determine the data that is sent and how it is read. While this can be prone to parsing errors, it gives you tremendous benefit in terms of data transfer speed over web services.

Here is a link to a detailed article on sockets and the support in Windows Phone 7.1: http://msdn.microsoft.com/en-us/library/hh202874(v=vs.92).aspx.

What are we going to do?

We are going to build a simple application for taking orders in a restaurant. There will be a windows phone 7 application for taking orders and there will be a Silverlight out of browser application for receiving/processing the orders that will run on your host desktop or laptop. The concept is that servers will take orders on the Windows Phone 7 devices and the host will receive the orders and send the status of the orders as they are done.

The servers will be notified on each order as it completes.

This application is based on the "Rock, Paper, Scissors" multicast application on msdn (http://msdn.microsoft.com/en-us/library/ff431744(v=vs.92).aspx).

So let’s get started!

Quick overview

At the very minimum, we need to build a server application that receives the data sent by the client. For the demo we chose a Silverlight (Out of Browser) application.

Note: We have to run the Silverlight application in "Out of Browser" mode with elevated permissions so that it can access the socket data received.

We need to agree on what data is sent to the host -> a table number, order information and spice level.

/// <summary>
/// When we receive the Order, we pass on the table number and other parameters
/// </summary>

public class OrderReceivedEventArgs : EventArgs
{
    public int tableNumber { get; set; }
    public int spiceLevel { get; set; }
    public string order { get; set; }
}

We will also display the Windows Phone 7 devices connected to the host. This helps the person managing the host to know how many servers are working at a time. This information comes from the "DeviceInfo" object. Here is a snippet of the declaration:

/// <summary>
/// The information about each device. This class must implement INotifyPropertyChanged as it is
/// bound to a datagrid using an observable collection.
/// </summary>
public class DeviceInfo : INotifyPropertyChanged
{
    private IPEndPoint _DeviceEndPoint;
    private string _DeviceOrServerName;
    public DeviceInfo(string deviceOrServerName, IPEndPoint endPoint)
    {
        _DeviceEndPoint = endPoint;
        _DeviceOrServerName = deviceOrServerName;
    }
}

Here is a screenshot of the host:

clip_image002

We also need the windows phone 7 clients to take the order, a simple application which takes in the above data and submits it.

Here is a screenshot of the windows phone 7 application:

clip_image004

As you can see, we have the name of the server at the top. This is currently application generated but as an extension we can provide the user the ability to sign in and use the sign in data to show the name of the server logged in.

We have two sliders:

1. The first slider is to choose the table number. It ranges from 1 to 10. This is a very simplistic approach for table selection and will work easily for even 20-30 tables as the slider is very precise and allows for easy touch selection.

2. The second slider is to choose the spice level. It comes primarily from my taste of spicy food but is also something widely specified while ordering food.

The range is set from 1 to 10.

The third element is a textbox to put order details. If you wish to extend this demo, you can add a scrolling selection of menu items and a datagrid to add each selected menu item. For this sample we have kept it simple to a text input.

And finally we need a button to send the order. That’s it!

The following key points should be noted:

1. RestaurantCommands class: This class contains the commands allowed in our socket application and must be common to the host and the recipient to understand the message sent and received.

2. UdpAnySourceMulticastChannel.cs and UdpPacketReceivedEventArgs.cs: These are two files we have taken from the sdk multicast application that contain the UDP multicast sockets code for joining the group, sending and receiving data.

3. Order class: This class handles all application communication. Communication for the application is made up of a number of commands that we have defined in the RestaurantCommand.cs class. These commands are the grammar, or set of actions, that we can transmit and receive and interpret.

Understanding the sample

Prerequisites: Install the Mango tools from http://create.msdn.com. This should give you Visual Studio Express 2010 and the Windows Phone SDK that you need to develop applications for Windows Phone. We are also running a Silverlight application on the host. Download Visual Studio c# express edition to get the required templates.

  • Launch Visual Studio and browse to the solution file and open it.
  • Note: The solution file has two startup projects. The "TakeMyOrder" windows phone 7 project and the "PointOfSaleApp" Silverlight application.
  • This is a multicast socket sample. To run this you need to deploy the windows phone 7 sample to the phone and run the Silverlight application on host.
  • Alternatively, if you do not have a phone, deploy the Silverlight application to another machine (say a Virtual Machine) and run the Windows Phone 7 app in an emulator on the host.
  • You cannot run the Silverlight application and the windows phone 7 application on the emulator on the same machine.
  • If you have multiple machines, phones, you can run the windows phone 7 application simultaneously on all of them. This will give you a feel for multiple servers taking orders and submitting them at the same time.
  • Since we are using UDP protocol, there is no guarantee that the messages sent are received. This is due to the fact that there is no peer to peer connection between two devices. Instead devices join a multicast group identified by an ip address and a port. However as you will see when you run the application, the communication is fairly reliable.

How it works:

  • Launch the Silverlight out of browser application.
  • Launch the windows phone 7 application on the phone or on an emulator running on another machine.
  • The host will show the name of the server and the end point address.
  • At this point you are ready to place an order.
  • On the windows phone 7 application, Use the table slider and choose a table from 1 to 10.
  • Enter an order. E.g. Fried rice with chicken and shrimp. Coke no ice etc.
  • Use the spice slider to set a spice level desired. 10 would be an excellent choice!
  • Click Order. At this point the windows phone 7 application sends the "SendOrder" command to all the devices on the group. Alternatively we could have filtered this to just send the order to the host.
  • On the host, the order is received and added to the "Incoming Orders" grid. This shows up with a status of "In Process" and a unique order id (based on number of orders received) is assigned.
  • Let’s say that we have a very fast kitchen and the order is ready as soon as we receive it. Check the checkbox next to the "In Process" order and click "Order Ready" button. The host sends the order status to all the devices on the network and updates the status in the grid. See below regarding INotifyPropertyChanged.
  • The Windows Phone 7 devices receive the order status on all devices. Alternatively we could have filtered it to just send to the device submitting the order.

Here is a screenshot after an order is complete:

clip_image006

Understanding the code

Here are the key pieces to understand about the code.

Joining the group: The devices join the group using the following key components:

/// <summary>
/// All communication takes place using a UdpAnySourceMulticastChannel.
/// A UdpAnySourceMulticastChannel is a wrapper we create around the UdpAnySourceMulticastClient.
/// </summary>
/// <value>The channel.</value>
private UdpAnySourceMulticastChannel Channel { get; set; }

/// <summary>
/// The IP address of the multicast group.
/// </summary>
/// <remarks>
/// A multicast group is defined by a multicast group address, which is an IP address
/// that must be in the range from 224.0.0.0 to 239.255.255.255. Multicast addresses in
/// the range from 224.0.0.0 to 224.0.0.255 inclusive are well-known reserved multicast
/// addresses. For example, 224.0.0.0 is the Base address, 224.0.0.1 is the multicast group
/// address that represents all systems on the same physical network, and 224.0.0.2 represents
/// all routers on the same physical network.The Internet Assigned Numbers Authority (IANA) is
/// responsible for this list of reserved addresses. For more information on the reserved
/// address assignments, please see the IANA website.
/// http://go.microsoft.com/fwlink/?LinkId=221630
/// </remarks>
private const string GROUP_ADDRESS = "224.0.1.11";

/// <summary>
/// This defines the port number through which all communication with the multicast group will take place.
/// </summary>
/// <remarks>
/// The value in this example is arbitrary and you are free to choose your own.
/// </remarks>
private const int GROUP_PORT = 54329;

The following command is issued to join the group:

//Send command to join the multi cast group
App.Order.Join(serverName);

And finally the join method opens the channel for communication.

/// <summary>
/// Join the multicast group.
/// </summary>
/// <param name="serverName">The server name I want to join as.</param>
/// <remarks>The server name is not needed for multicast communication. it is
/// used in this example to identify each member of the multicast group with
/// a friendly name. </remarks>
public void Join(string serverName)
{
    if (IsJoined)
       {
           return;
    }

       // Store my player name
       _serverName = serverName;

       //Open the connection
       this.Channel.Open();
}

We subscribe to the following events for processing:

/// <summary>
/// Register for events on the multicast channel.
/// </summary>
private void RegisterEvents()
{
    // Register for events from the multicast channel
       this.Channel.Joined += new EventHandler(Channel_Joined);
       this.Channel.BeforeClose += new EventHandler(Channel_BeforeClose);
       this.Channel.PacketReceived += new EventHandler<UdpPacketReceivedEventArgs>(Channel_PacketReceived);
}

Of particular note is the “PacketReceived” event. We process all commands received (Device and Host) in this event handler. Simply put, we parse the incoming message and identify the command being sent. Based on the command and the number of arguments we further identify the action to take.

Sending the order: The following command is issued when the user clicks the Order button:

App.Order.SendOrder(txtOrder.Text, TableSlider.Value.ToString(), spiceSlider.Value.ToString());

/// <summary>
/// Send the order
/// </summary>
/// <param name="Order"></param>
/// <param name="tableNumber"></param>
/// <param name="spiceLevel"></param>
public void SendOrder(string Order,string tableNumber, string spiceLevel)
{
    if (this.Channel != null)
       {
           //Send order to all devices. Only the server will process the send order command. Others will simply ignore it.
                this.Channel.Send(RestaurantCommands.SendOrderFormat, _serverName, Order, tableNumber, spiceLevel);
    }
}

Our “SendOrderFormat” looks like this:

public const string SendOrder = "SO";
public const string SendOrderFormat = SendOrder + CommandDelimeter + "{0}" + CommandDelimeter + "{1}" + CommandDelimeter + "{2}" + CommandDelimeter + "{3}";

Here is the code for the Send method:

/// <summary>
/// Sends the specified format. This is a multicast message that is sent to all members of the multicast group.
/// </summary>
/// <param name="format">The format.</param>
/// <param name="args">The args.</param>
public void Send(string format, params object[] args)
{
    try
    {
        if (this.IsJoined)
        {
            byte[] data = Encoding.UTF8.GetBytes(string.Format(format, args));
            this.Client.BeginSendToGroup(data, 0, data.Length, new AsyncCallback(SendToGroupCallback), null);
        }
    }
    catch (SocketException socketEx)
    {

        // See if we can do something when a SocketException occurs.
        HandleSocketException(socketEx);
    }
    catch (InvalidOperationException)
    {
        Debug.WriteLine("BeginSendToGroup IOE");
    }
}

So, as we can see, based on the format the message is formatted and transmitted.

Receiving the order:

On the host the message is received by the handler defined for the “PacketReceived” event: void Channel_PacketReceived(object sender, UdpPacketReceivedEventArgs e)

We parse the message and identify the command.

string message = e.Message.Trim('\0');
string[] messageParts = message.Split(RestaurantCommands.CommandDelimeter.ToCharArray());

else if (messageParts.Length == 5 && messageParts[0]== RestaurantCommands.SendOrder)
{
    //Status of order received
       OrderReceivedEventArgs args = new OrderReceivedEventArgs();
       args.tableNumber = Convert.ToInt32(messageParts[3]);
       args.spiceLevel = Convert.ToInt32( messageParts[4]);
       args.order = messageParts[2];
       if (DataReceivedFromDevice != null)
       {
           DataReceivedFromDevice(this, args);
    }
}

It’s a very simple communication mechanism. Once we have identified, parsed and created our arguments for the data received method, we raise it.

In our host application we handle the event and add the incoming order to the orders collection:

/// <summary>
/// Handles incoming orders
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Order_DataReceivedFromDevice(object sender, OrderReceivedEventArgs e)
{
    int OrderID = App.OrdersCollection.Count +1;
       Orders objOrders = new Orders(OrderID, e.tableNumber, e.spiceLevel, e.order);
       App.OrdersCollection.Add(objOrders);
}

Known Issues

· Once in a while you will receive an error when you stop debugging:

· File or assembly name ‘System.Net.debug.resources, Version=2.0.5.0, Culture=en-US, PublicKeyToken=7cec85d7bea7798e’, or one of its dependencies, was not found.

· This is a known issue as indicated here http://forums.create.msdn.com/forums/p/89666/537141.aspx . Sometimes after this error is raised, you have to close visual studio and re-launch it.

INotifyPropertyChanged

This interface has to be implemented on the objects we use to bind to the datagrids. Even if the object collections are declared like shown below, the user interface does not update unless the properties in the object itself raise the property changed event.

public static ObservableCollection<DeviceInfo> Devices = new ObservableCollection<DeviceInfo>();

Sending Order Status: Similar to the above, a similar mechanism is implemented to send the order status:

/// <summary>
/// Sends the order status
/// </summary>
/// <param name="OrderID"></param>
/// <param name="status"></param>
public void SendOrderStatus(int OrderID, string status)
{
    if (this.Channel != null)
{
           //Send order to all devices. Only the server will process the send order command. Others will simply ignore it.
this.Channel.Send(RestaurantCommands.ReceiveOrderFormat, _serverName, OrderID, status);
}
}

public const string ReceiveOrder = "RO";
        
public const string ReceiveOrderFormat = ReceiveOrder + CommandDelimeter + "{0}" + CommandDelimeter + "{1}" + CommandDelimeter + "{2}";

else if (messageParts.Length == 4 && messageParts[0] == RestaurantCommands.ReceiveOrder)
{
    //Status of order received
       OrderStatusReceivedEventArgs args = new OrderStatusReceivedEventArgs();
       args.orderId = Convert.ToInt32(messageParts[2]);
       args.orderStatus = messageParts[3];
       if (DataReceivedFromDevice != null)
       {
        DataReceivedFromDevice(this, args);
    }
}

/// <summary>
/// Shows a message box with the order status
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Order_DataReceivedFromDevice(object sender, OrderStatusReceivedEventArgs e)
{
    DiagnosticsHelper.SafeShow("Order Status of '" +e.orderStatus + "' Received For Order:" + e.orderId.ToString());
}

Summary

So, using the helpers provided it is fairly simple to implement an application using sockets. This application can be turned into a comprehensive restaurant application by simply extending some features as noted and many others:

  • Add the ability to select from a menu
  • Add the ability to see the pending orders on the devices
  • Add the ability to sign in

The basic steps to building a socket application are:

  • Decide on the type of socket application: Multicast (UDP) or UniCast (TCP).
  • Decide on the commands.
  • Communicate.
  • Process.

This should give you a good overview of sockets support in windows phone 7. Check out the code examples provided at http://msdn.microsoft.com/en-us/library/hh202874(v=vs.92).aspx

To download this entire sample Windows Phone application using sockets, click the Download Code button below:

download

Tomorrow, Matt Eland is going to walk you through using App Connect (also known as search extensibility) to get your application in front of users, even if they haven’t installed it on their device.  See you then!

toolsbutton

Tags

5 responses to “31 Days of Mango | Day #21: Sockets”

  1. […] Days of Mango | Day #19: Tilt Effects, Day #20: Creating Ringtones & Day #21: Sockets – Jeff Blankenburg’s 31 days of Mango series continues with three guest posts, the first from […]

  2. […] Der Originalartikel befindet sich hier: Day #21: Sockets. […]

  3. […] 31 Days of Mango | Day #21: Sockets […]

  4. […] Este artículo es una traducción de Day 21: Sockets, puedes encontrarlo aquí en su versión origin… […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create a website or blog at WordPress.com

%d bloggers like this: