Silverlight and WebSockets

I was intrigued by this post from Tomek which has links to a prototype of an application built with Silverlight but using WebSockets.

It’s kind of interesting because running the application in IE9 gives me;

image

now, the only bit of that application that’s actually Silverlight is the highlighted blue square which is providing a client side implementation of WebSockets to the browser based code which is just HTML/JS. If I run in Chrome I see;

image

because Chrome has support for WebSockets already and so the sample switches out the Silverlight functionality.

If you’ve not read about WebSockets then there’s a starter here and info on the protocol up here.

If you’ve programmed with connected, TCP sockets then you know that the model is essentially;

  1. Server listens. Client connects.
  2. Connection stays open during lifetime of communication.
  3. Client and Server send stuff any time they like in a full-duplex manner.

So, traditional sockets are great in that they allow full duplex comms such as when the server wants to notify the client that something has happened but they’re not so great in that they require an open connection which tends to limit your server side scalability. They’re also not so great when it comes to crossing boundaries that only allow HTTP on port 80 or 443.

If you’ve programmed with HTTP then you know that the model is essentially;

  1. Server listens. Client connects.
  2. Client sends request.
  3. Server sends response.
  4. Client (generally) disconnects as soon as that response comes back.

and so HTTP is a great use of sockets in that it makes the model a lot more scalable by not requiring a permanent connection between the client and the server and server-side state but, because of that lack of connection, you can’t have the server notify the client of something because, generally, the client and server have no connection at any particular point in time.

Now, of course you can use HTTP in various ways to try and give the illusion that the server does have a connection to the client and that’s normally done by just having the client poll the server on some period essentially asking “Do you have anything for me right now?” with the expectation that the answer from the server will frequently be “no”.

So, a server wanting to “notify” a client simply has to put its notification data into a database and wait for the next time that client polls when it will be able to deliver the notification.

There are even special HTTP tricks around this such as the “long polling” trick where the client polls on some frequency but holds the HTTP connection open longer than it usually would in the hope that during the lifetime of the connection the server will find that it has something it wants to push to the client and will send it down the already open connection. Clearly, there’s a balance here between how frequently a client polls and how long it keeps that connection open when it does poll.

These sort of techniques are sometimes known as Comet and this idea of “long polling” is built into the WCF Polling Dupleximplementation that can be used from Silverlight applications.

As an aside the place where I’ve seen interest around this kind of functionality is from developers building financial apps who need low latency on server-driven data change notifications.

WebSockets comes along (or is coming along) and again blurs the HTTP model and the raw TCP model. The essence of it is;

  1. Client makes HTTP connection over (e.g.) port 80/443.
  2. Client’s request uses a combination of Connection/Upgrade header to request “WebSockets”.
  3. If the server understands that (and it may well not today) then the client and server now can keep the socket open and send data back and forward to each other as they require.
    1. Data flows at UTF-8 with markers so that the client and server can denote “start” and “end” of each message which I guess makes life a lot easier for the programmer who has to handle those messages.

Naturally, there’s a whole tonne more complexity to it than that but that’s the essence.

Then there’s the API that a browser might expose around this stuff which is documented up here – browser support for this is “mixed” at the moment hence Tomek’s example using Silverlight to “bridge” that gap.

I ended up debugging the Javascript a little to see what’s going on in the sample – it’s not often that I can get enticed into debugging Javascript but this drew me in.

Firstly, the code determines whether the browser already has WebSocket support;

  if (window.WebSocket == undefined) {
        $(document).ready(function () {
            var script = document.createElement("script");
            document.body.appendChild(script);
            script.src = 'Silverlight.js';
            var slhost = document.createElement("div");
            document.body.insertBefore(slhost, document.body.firstChild);
            //document.body.appendChild(slhost);
            slhost.innerHTML = "<object/>"; // Snipped for brevity
        });
    }
    else {
        $.slws._loaded = true;
    }

if it doesn’t then it injects an additional DIV onto the page and hosts a Silverlight XAP within that DIV. When that element is ready it then runs this code;

       var slCtl = sender.getHost();

        window.WebSocket = function (url) {
            this.slws = slCtl.Content.services.createObject("websocket");
            this.slws.Url = url;
            this.readyState = this.slws.ReadyState;
            var thisWs = this;
            this.slws.OnOpen = function (sender, args) {
                thisWs.readyState = thisWs.slws.ReadyState;
                if (thisWs.onopen) thisWs.onopen();
            };
            this.slws.OnMessage = function (sender, args) {
                if (args.Message.charAt(0) == '"' && thisWs.onmessage)
                    thisWs.onmessage({ data: args.Message });
            };
            this.slws.OnClose = function (sender, args) {
                thisWs.readyState = thisWs.slws.ReadyState;
                if (thisWs.onclose) thisWs.onclose();
            };
            this.slws.Open();
        };

        window.WebSocket.prototype.send = function (message) {
            if (message.charAt(0) != '"')
                message = '"' + message + '"';
            this.slws.Send(message);
        };

        window.WebSocket.prototype.close = function() {
            this.slws.Close();
        };

That is – this code will only run if the browser doesn’t support WebSockets already and what it does is to wire upwindow.WebSocket to something that implements the WebSockets API. If the browser already support WebSockets then there’s no need for any of this.

Where does that implementation come from? The Silverlight code. You can see here from the Javascript that it is reaching into the Silverlight code and creating an object (i.e. a .NET object) that has registered itself under the name of “websocket”and from the Javascript here we can see that we expect that object to have events OnOpen, OnMessage, OnClose and methods called Open, Send, Close.

From there on in the rest of the Javascript code is abstracted from whether the WebSockets implementation is a native browser one or a Silverlight one.

Neat.

So, what does the code inside of the Silverlight app look like – I must admit, I took Reflector to it. At application startup it registers a .NET type so that it can be instantiated from Javascript with the name “websocket”;

image

and that type WebSocket (in the packaged System.ServiceModel.WebSockets.dll) is marked as being scriptable;

image 

and offers the expected interface around Open/Close/Send and events OnOpen/OnMessage/OnClose and if you have a poke around in the SeventyFiveWebSocketProtocol class you’ll find it sending an HTTP GET with the relevant Connection andUpgrade headers and processing the server’s response.

Not only is this a nice example of WebSockets but it’s also a nice example of;

  1. Programming across the HTML bridge in Silverlight in order to use .NET types from Javascript, invoke functions on those types and handle events from them.
  2. Plugging a cross-browser incompatibility in a really slick way with some Silverlight code – relying on Microsoft to test that Silverlight does the right thing cross-browser and cross-platform rather than waiting until all the browsers implement some feature (in this case, WebSockets).

The only remaining “mystery” to me around this sample was what’s going on with the server-side as I’m not sure whether you could build a websockets server on IIS purely at the WCF layer.

My first thought would be that it’d require some IIS support to get that going so I’ll need to ponder on that and perhaps ask Tomek whether he can explore a little more around what’s happening on the server side.


Posted  Tue, Jul 27 2010 12:03 PM by  mtaulty
Filed under: 
Comments
Chad W Stoker wrote  re: Silverlight and WebSockets
on Tue, Jul 27 2010 6:02 PM

Is there another web server-side platform that would support this? For instance, Apache, Web-Sphere, or other?

mtaulty wrote  re: Silverlight and WebSockets
on Tue, Jul 27 2010 11:15 PM

Hi Chad,

I'm not sure to be honest - I think at the moment on the Windows platform you can either;

1) Use IIS

2) Use self-hosted HTTP via (e.g.) the .NET HttpListener class.

both of those use HTTP.SYS and, as far as I know, HTTP.SYS does not support this idea of websockets.

Other web servers? I don't know them very well but a web search seems to suggest that Apache doesn't yet do it but there might be a plug-in that makes it happen.

Mike.

DotNetShoutout wrote  Silverlight and WebSockets - Mike Taulty
on Fri, Jul 30 2010 5:45 PM

Thank you for submitting this cool story - Trackback from DotNetShoutout

Anonymous wrote  re: Silverlight and WebSockets
on Fri, Jul 30 2010 7:18 PM

Theoretically, Silverlight can be hosted on ANY web server if you register the proper MIME types.  Silverlight runs entirely in the broweser.

Of course, you need a server to talk to, but if you are doing pure sockets programming, it should to any sockets point on any type of server of device.

mtaulty wrote  re: Silverlight and WebSockets
on Fri, Jul 30 2010 11:35 PM

Hi,

It's not really theoretical - you *can* host a Silverlight application on any web server you like.

However, whether that Silverlight application can then talk to that sockets on that server or any other server depends on a whole bunch of factors including whether the application is *trusted* or not, whether the application is using ports 4502-4534 or not and cross domain policy files.

However, I wasn't really talking about sockets here. I was talking about websockets and websockets are not something that's built into IIS today and so that was why I was debating it.

Make sense?

Mike.

Howard van Rooijen wrote  re: Silverlight and WebSockets
on Sun, Aug 1 2010 12:27 PM

Nice article - I've actually spent the week working to get Silverlight 4 and Websockets working - so Tom's post and this have been a great help - I've ended up using Node.js / Sockets.io to host the websocket as part of a prototype and have to say it works a treat.

Howard

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值