背景
在传统方式下,很多网站为了实现即时通讯,所用的技术都是轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对伺服器发出HTTP request,然后由伺服器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向伺服器发出请求,然而HTTP request 的header是非常长的,里面包含的数据可能只是一个很小的值,这样会占用很多的带宽和服务器资源。
而比较新的技术去做轮询的效果是Comet,使用了AJAX。但这种技术虽然可达到双向通信,但依然需要发出请求,而且在Comet中,普遍采用了长链接,这也会大量消耗服务器带宽和资源。
面对这种状况,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽并达到实时通讯。WebSocket 是HTML5一种新的协议。它是实现了浏览器与伺服器的双向通讯。
简单的讲,通过WebSocket,可以在浏览器和服务器间建立一个TCP长连接,服务器可以实现主动推送数据至客户端。目前为止,Chrome和Safari的最新版本浏览器已经支持WebSockets了(win8测试版中的IE10也是支持的)。
客户端
在支持WebSocket的浏览器中,可以直接在Javascript中通过WebSocket对象来实现通信。WebSocket对象主要通过onopen,onmessage,onclose即onerror四个事件实现对socket消息的异步响应。一个简单的示例如下:
var socket = new WebSocket("ws://localhost:8080/");
socket.onopen = function () {
alert("Socket has been opened!");
}
socket.onmessage = function (msg) {
alert(msg); //Awesome!
}
关于其详细信息可以查看W3网站上的WebSocket API
这里附一个网上找的简单的聊天页面的实现:

2 < head >
3 < title >WebSocket </ title >
4 < style >
5 html, body {
6 font : normal 0.9em arial,helvetica ;
7 }
8
9 #log {
10 width : 440px ;
11 height : 200px ;
12 border : 1px solid #7F9DB9 ;
13 overflow : auto ;
14 }
15
16 #msg {
17 width : 330px ;
18 }
19 </ style >
20 < script >
21 var socket;
22
23 function init() {
24 var host = " ws://localhost:8080/ " ;
25 try {
26 socket = new WebSocket(host);
27 socket.onopen = function (msg) {; };
28 socket.onmessage = function (msg) { log(msg.data); };
29 socket.onclose = function (msg) { log( " connection closed. " ); };
30 }
31 catch (ex) { log(ex); }
32 $( " msg " ).focus();
33 }
34
35 function send() {
36 var txt, msg;
37 txt = $( " msg " );
38 msg = txt.value;
39 if ( ! msg) { alert( " Message can not be empty " ); return ; }
40 txt.value = "" ;
41 txt.focus();
42 try { socket.send(msg); } catch (ex) { log(ex); }
43 }
44
45 window.onbeforeunload = function () {
46 try {
47 socket.send( ' quit ' );
48 socket.close();
49 socket = null ;
50 }
51 catch (ex) {
52 log(ex);
53 }
54 };
55
56
57 function $(id) { return document.getElementById(id); }
58 function log(msg) { $( " log " ).innerHTML += " <br> " + msg; }
59 function onkey(event) { if (event.keyCode == 13 ) { send(); } }
60 </ script >
61 </ head >
62 < body onload ="init()" >
63 < h3 >WebSocket </ h3 >
64 < br >
65 < br >
66 < div id ="log" ></ div >
67 < input id ="msg" type ="textbox" onkeypress ="onkey(event)" />
68 < button onclick ="send()" >Send </ button >
69 </ body >
70 </ html >
服务器端
在.Net 4.5中,在System.Web.WebSockets和System.Net.WebSocket名字空间实现了对WebSocket的支持,其中前者主要用于Asp.net框架。如下是一个简单的EchoServer的实现。
class WebSocketServer
{
public WebSocketServer()
{
Start();
}
async void Start()
{
var listener = new HttpListener();
listener.Prefixes.Add("http://localhost:8080/");
listener.Start();
while (true)
{
var context = await listener.GetContextAsync();
Console.WriteLine("connected");
var websocketContext = await context.AcceptWebSocketAsync(null);
ProcessClient(websocketContext.WebSocket);
}
}
async void ProcessClient(WebSocket websocket)
{
var data = new byte[1500];
var buffer = new ArraySegment<byte>(data);
while (true)
{
var result = await websocket.ReceiveAsync(buffer, CancellationToken.None);
if (result.CloseStatus != null)
{
Console.WriteLine("socket closed");
websocket.Abort();
return;
}
Console.WriteLine(">>> " + Encoding.UTF8.GetString(data, 0, result.Count));
await websocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
}
}
}
得益于C#的async特性,实现WebSocket服务器是非常简洁的,不过我没有找到实现客户端的方法,如果谁知道望指点一下。但令人不解的是这个api只支持win8(虽然从MSDN上来看是支持win7等其它系统的),不知道最后正式版会不会去掉这个操作系统的限制。
要在非win8环境下实现WebSocket,可以试一下SuperWebSocket(服务器端)和WebSocket4Net(客户端)这两个开源库。当然,非.net的实现也是非常多的,常见的就有phpwebsockets,jWebSocket,web-socket-ruby等,这里就不一一列举了。
由于现在这段时间较忙,对于WebSocket也只是处于概念性的学习,浅尝辄止。如果有时间的话后续再写一下关于WebSocket协议和实现的相关文章。