• HTML5中的WebSocket


    背景

    在传统方式下,很多网站为了实现即时通讯,所用的技术都是轮询。轮询是在特定的的时间间隔(如每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

    这里附一个网上找的简单的聊天页面的实现:

    View Code
     1 <html>
     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的实现也是非常多的,常见的就有phpwebsocketsjWebSocketweb-socket-ruby等,这里就不一一列举了。

    由于现在这段时间较忙,对于WebSocket也只是处于概念性的学习,浅尝辄止。如果有时间的话后续再写一下关于WebSocket协议和实现的相关文章。

  • 相关阅读:
    getWidth() 和 getMeasuredWidth()的区别
    解决 win7 注册com组件失败问题
    Documentation/PCI/pci-iov-howto.txt
    Android Migrate Android Code
    struts2 18拦截器详解(九)
    使用Maven模板创建项目
    转换基于Maven的Web应用程序支持Eclipse IDE
    转换基于Maven的Java项目支持Eclipse IDE
    Eclipse构建Maven项目
    NetBeans IDE集成Maven
  • 原文地址:https://www.cnblogs.com/TianFang/p/2429954.html
Copyright © 2020-2023  润新知