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;
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;
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;
- Server listens. Client connects.
- Connection stays open during lifetime of communication.
- 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;
- Server listens. Client connects.
- Client sends request.
- Server sends response.
- 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;
- Client makes HTTP connection over (e.g.) port 80/443.
- Client’s request uses a combination of Connection/Upgrade header to request “WebSockets”.
- 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.
- 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”;
and that type WebSocket (in the packaged System.ServiceModel.WebSockets.dll) is marked as being scriptable;
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;
- 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.
- 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
Comments
Is there another web server-side platform that would support this? For instance,Apache,Web-Sphere,or other?
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.
Thank you for submitting this cool story - Trackback from DotNetShoutout
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.
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
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。