sockets-for-pcl: TCP and UDP sockets from the comfort of your PCL

Over Christmas last year, Xamarin ran a Holiday Plugin Contest encouraging the development of open source cross-platform libraries for Xamarin iOS, Android and Windows Phone/Store. The contest was enough of a motivation to look seriously at a problem I'd been wanting to solve for a while and in the process create my first open source library: sockets-for-pcl.

What is it?

Sockets for PCL is designed to make the use of TCP and UDP sockets in a PCL possible without needing to introduce DI or your own abstractions. As it is currently, there is no PCL profile supporting mobile platforms that includes access to socket classes. The likely reason is differences between classes supporting Sockets in the .NET Framework (used by Desktop, Web and Xamarin) and the WinRT Framework (used by Windows Phone 8+ / Windows Store apps). Sockets for PCL abstracts over the helper classes in each of these frameworks to give you a simple async API against which to write your socket code:

Class Description .NET Abstraction WinRT Abstraction
TcpSocketListener Bind to a port and accept TCP socket connections. TcpListener StreamSocketListener
TcpSocketClient Connect to a TCP endpoint with bi-directional communication. TcpClient StreamSocket
UdpSocketReceiver Bind to a port and receive UDP messages. UdpClient DatagramSocket
UdpSocketClient Send messages to arbitrary endpoints over UDP. UdpClient DatagramSocket
UdpSocketMulticastClient Send and receive UDP messages within a multicast group. UdpClient DatagramSocket

Getting started with the library is simple. After adding the NuGet package to your PCL and each native platform's project, you can write code directly against the classes in your PCL. Because of the way the NuGet package is structured, each native platform project will make use of the platform specific code without any work on your part.

What's it useful for?

Any time you are working with sockets and are considering support for multiple platforms on .NET, a PCL-based approach is the best approach. Sockets for PCL is written against PCL profile 259, so supports Xamarin.iOS (classic/unified), Xamarin.Android, Windows Store, Windows Phone 8, Windows Phone 8.1 and Windows Desktop (NET45). Sockets for PCL allows you to write your socket code once in your PCL and have it run on all the aforementioned platforms. With frameworks like Xamarin.Forms and CocosSharp, where a majority of your code lives in the PCL already, this is a huge boon. It also opens the door to very simple ad-hoc multiplatform device communications. Again, this is particularly useful for CocosSharp, where supporting multiplatform multiplayer would preclude you from using each native platform's game/multiplayer communications frameworks.

How do I use it?

Sockets for PCL presents a simple API TCP and UDP sockets. Apart from the abstractions over the underlying framework APIs however, it makes no assumptions about how you will use the library and provides you the lowest level of access that each protocol supports - for TCP, these are bytestreams represented by ReadStream and WriteStream on TcpSocketClient, and for UDP byte[] datagrams are sent and received via SendToAsync and the MessageReceived eventhandler. Below is an example of listening for and receiving UDP traffic.

Listen for UDP traffic
var listenPort = 11011;  
var receiver = new UdpSocketReceiver();

receiver.MessageReceived += (sender, args) =>  
{
  // get the remote endpoint details and convert the received data into a string
  var from = String.Format("{0}:{1}", args.RemoteAddress, args.RemotePort);
  var data = Encoding.UTF8.GetString(args.ByteData, 0, args.ByteData.Length);

  Debug.WriteLine("{0} - {1}", from, data);
};

// listen for udp traffic on listenPort
await receiver.StartListeningAsync(listenPort);  
Send UDP traffic
var port = 11011;  
var address = "127.0.0.1";

var client = new UdpSocketClient();

// convert our greeting message into a byte array
var msg = "HELLO WORLD";  
var msgBytes = Encoding.UTF8.GetBytes(msg);

// send to address:port, 
// no guarantee that anyone is there 
// or that the message is delivered.
await client.SendToAsync(msgBytes, address, port);  

See the github page for more examples.

Cool, how do I make a library like this?

So glad you asked. That will be the topic for a future post..