WEBSITE

Silverlight Recipes : Using Sockets to Communicate over TCP (part 1)

7/21/2012 11:33:16 AM
1. Problem

You need a Silverlight application to communicate with server-side applications using TCP sockets.

2. Solution

Use the System.Net.Sockets.Socket type and related types to connect and exchange data with a server-side TCP socket.

3. How It Works

Silverlight supports socket communication through the System.Net.Sockets.Socket type. This class exposes an API to connect to a TCP endpoint at a specified IP address/port combination, send data to that endpoint, and receive data from that endpoint.

However, the Socket type in Silverlight is slightly different from the equivalent type in the desktop and server versions of the .NET Framework; it supports only the client behavior and has no server abilities. In other words, unlike the desktop or the server version, the Silverlight version does not expose the ability to go into a listen mode and accept incoming connections. Therefore, although Silverlight applications can easily use TCP sockets to exchange data with server applications, a Silverlight application cannot act as a socket-based server.

3.1. The Sockets API in Silverlight

All socket functionality in Silverlight works asynchronously, thus avoiding any blocking calls that would prevent the main thread from blocking execution while waiting for any such call completion. However, the design pattern for the Socket's asynchronous APIs is somewhat different from the previously discussed Begin-End pattern, as you see in a moment.

The life of a socket connection begins by creating a new instance of a Socket and calling the ConnectAsync() method on the socket instance. The call to ConnectAsync() is nonblocking and returns immediately. To be notified on completion of the connection process, you can attach a handler to the Completed event of the SocketAsyncEventArgs parameter, which then is called back by the runtime. The following code excerpt shows a sample of this:

//create a new socket
Socket ClientSocket = new Socket(AddressFamily.InterNetwork,
                                  SocketType.Stream,
                                  ProtocolType.Tcp);
//create a new SocketEventArgs
SocketAsyncEventArgs sockEvtArgs = new SocketAsyncEventArgs {
  RemoteEndPoint = new IPEndPoint(IPAddress.Parse("192.168.0.10"), 4502),
  UserToken = MyData };
//connect a completion handler
sockEvtArgs.Completed += new EventHandler<SocketAsyncEventArgs>(
    delegate(object sender, SocketAsyncEventArgs e)
    {
      if (e.SocketError == SocketError.Success)
      {

        //connection succeeded - do something
      }
    });
//connect asynchronously
ClientSocket.ConnectAsync(sockEvtArgs);

As you can see, the Socket construction parameters let you specify the following:

  • The type of addressing scheme used between IPv4 or IPv6 (which also enables IPv4) using the AddressFamily enumeration. To specify an IPv4 addressing scheme, use AddressFamily.InterNetwork; for IPv6, use AddressFamily.InterNetworkV6.

  • The SocketType (the only available value is Stream).

  • The ProtocolType (the only supported protocol is TCP).

Alternatively, you can set all the enumeration values to unspecified, and the values are inferred at runtime.

The endpoint being connected to is specified as the RemoteEndPoint property of the SocketEventArgs parameter. You can set it to an instance of IPEndPoint if you know the exact IP address or that of a DnsEndPoint if you have a hostname and want the DNS system to translate it to an IP address for you. Additionally, you need to supply the port. You can also supply any user state in the UserToken parameter.

When the connection is made, the Completed event handler is called, and further information is made available to you through the SocketAsyncEventArgs instance passed into the handler. The SocketError property gives you a success status or the type of error that was encountered, and the UserToken parameter can be used to extract any supplied user state.

There is a static version of ConnectAsync(), which behaves similarly. Because you do not explicitly create a Socket instance to use the static version, a connected Socket instance is made available to you through the ConnectSocket property on the SocketEventArgs instance in the Completed handler.

After you are connected, you can begin sending and receiving data. To send data, you can use the SendAsync() method. The data to be sent must be represented as a byte[] and can be copied to the SocketAsynceventArgs.Buffer using the SetBuffer() method, as shown here:

SocketAsyncEventArgs sockEvtArgsSend = new SocketAsyncEventArgs();
sockEvtArgsSend.SetBuffer(MyData, 0, MyData.Length);
sockEvtArgsSend.Completed +=
  new EventHandler<SocketAsyncEventArgs>(SendRequest_Completed);
ClientSocket.SendAsync(sockEvtArgsSend);

Receiving data uses a similar implementation. To receive data, you allocate a byte[] and assign it using the SocketAsyncEventargs.SetBuffer() method as the receiving buffer, followed by a call to ReceiveAsync(). Note that the Silverlight socket implementation gives you no indication when you are about to receive data from a remote endpoint; nor can you poll the socket from time to time. Consequently, when the call to ReceiveAsync() returns in the Completed handler, you may want to execute the code to receive again, thus keeping your client socket in a continuous receive mode. The following code shows such an arrangement:

private void ReceiveMessage()
{
  //allocate memory
  byte[] ReceiveBuffer = new Byte[1024];
  SocketAsyncEventArgs sockEvtArgsReceive = new SocketAsyncEventArgs();
  //set the receive buffer
  sockEvtArgsReceive.SetBuffer(ReceiveBuffer, 0, 1024);
  sockEvtArgsReceive.Completed +=
    new EventHandler<SocketAsyncEventArgs>(Receive_Completed);
  //receive
  ClientSocket.ReceiveAsync(sockEvtArgsReceive);
}
void Receive_Completed(object sender, SocketAsyncEventArgs e)
{
  if (e.SocketError == SocketError.Success)
  {
    //switch context
    ParentPage.Dispatcher.BeginInvoke(new Action(delegate

{
      //access the received data
      byte[] Message = new byte[e.BytesTransferred];
      Array.Copy(e.Buffer, 0, Message, 0, e.BytesTransferred);
      //do something to process the received message

      //keep receiving
      ReceiveMessage();
    }));
  }
}

NOTE

The Completed handlers are called on a background thread, necessitating a context switch using Dispatcher, before you can invoke code running on the main UI thread.

3.2. Cross-Domain Policy and Port Requirements

Silverlight applications using sockets have to satisfy cross-domain policy requirements to access remote socket servers. There is also a restriction on the range of ports that a Silverlight client can connect to—the port must be within the inclusive range of 4502 to 4534.

4. The Code

The code sample for this recipe builds a simple one-to-one chat application that consists of a server program that acts as the listener and the gateway for exchanging text-based messages between Silverlight clients.

4.1. Running the Sample Code

To start the whole environment, you must first start up the sockets server and the policy server. Both of these are console programs and can be started either from the command line or from inside Visual Studio if you intend to start them in debug mode. The sockets server, which is named ChatBroker.exe, accepts one parameter on the command line: the port number you want it to listen on. Ensure that this is within the allowed port range of 4502 to 4534, inclusive. If you are debugging this from within Visual Studio, you can specify the parameter in your project's Debug properties page. The policy server is called PolicyServer.exe and does not need any startup parameters.

When you have the server instances up and running, you can then start (either in debug mode or by browsing to the page) the client. Figure 1 shows the various states of the Silverlight client.

Figure 1. Various states of the Silverlight chat client

You can specify the IP address and the port at which the sockets server is listening, as well as a name that you want to use in the conversation. After the user logs in, the client displays a list of all other participants currently connected to the server. You can click a participant and start a conversation. To simulate multiple participants, open multiple instances of the client and log in with multiple names.

Other  
  •  Microsoft ASP.NET 3.5 : The HTTP Request Context - The global.asax File
  •  Microsoft ASP.NET 3.5 : The HTTP Request Context - Initialization of the Application
  •  Free Email Everywhere and Anytime
  •  IIS 7.0 : Managing Web Sites - Administrative Tasks - Limiting Web Site Usage, Configuring Web Site Logging and Failed Request Tracing
  •  IIS 7.0 : Managing Web Sites - Administrative Tasks - Adding a New Web Site
  •  IIS 7.0 : Managing Worker Processes and Requests
  •  Websocket: Internet In Real Time
  •  IIS 7.0 : Managing Application Pools (part 3) - Advanced Application Pool Configuration, Monitoring Application Pool Recycling Events
  •  IIS 7.0 : Managing Application Pools (part 2) - Managing Application Pool Identities
  •  IIS 7.0 : Managing Application Pools (part 1) - Application Pool Considerations, Adding a New Application Pool
  •  
    Top 10
    Review : Sigma 24mm f/1.4 DG HSM Art
    Review : Canon EF11-24mm f/4L USM
    Review : Creative Sound Blaster Roar 2
    Review : Philips Fidelio M2L
    Review : Alienware 17 - Dell's Alienware laptops
    Review Smartwatch : Wellograph
    Review : Xiaomi Redmi 2
    Extending LINQ to Objects : Writing a Single Element Operator (part 2) - Building the RandomElement Operator
    Extending LINQ to Objects : Writing a Single Element Operator (part 1) - Building Our Own Last Operator
    3 Tips for Maintaining Your Cell Phone Battery (part 2) - Discharge Smart, Use Smart
    REVIEW
    - First look: Apple Watch

    - 3 Tips for Maintaining Your Cell Phone Battery (part 1)

    - 3 Tips for Maintaining Your Cell Phone Battery (part 2)
    VIDEO TUTORIAL
    - How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 1)

    - How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 2)

    - How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 3)
    Popular Tags
    Video Tutorail Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Exchange Server Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe Photoshop CorelDRAW X5 CorelDraw 10 windows Phone 7 windows Phone 8 Iphone