WebSocket使用

一、概述

HTML5 WebSockets是HTML5中最强大的通信功能,它定义了一个全双工通信信道,仅通过Web上的一个Socket即可进行通信。

目前实时Web应用的实现方式,大部分是围绕轮询和其他服务器端推送技术展开的,Comet、轮询、长轮询、流(streaming)解决方案,所有这些提供实时数据的方式包含有大量额外的、不必要的报头数据,会造成传输延迟。最重要的是为了在半双工HTTP的基础上模拟全双工通信,目前的许多解决方案都是使用了两个连接:一个用于下行数据流,另一个用于上行数据流。这两个连接的保持和协作也会造成大量的资源消耗,并增加了复杂度。

WebSockets就是解决以上问题的方案。为了建立WebSocket通信,客户端和服务器在初始握手时,将HTTP协议升级到WebSocket协议。

 

现在WebSocket服务器有很多,还在开发中的更多。有一下几种:

  • Kaazing WebSocket Gateway:一种基于Java的WebSocket网关。
  • mod_pywebsocket:一种基于Python的Apache HTTP服务器扩展。
  • Netty:一种包含WebSocket的Java框架。
  • node.js:一种驱动多个WebSocket服务器的服务器端JavaScript框架。
对于非原生支持WebSocket的浏览器来说,Kazzing的WebSocket网关包含了完整的客户端浏览器WebSocket模拟支持。

二、HTML5 WebSockets API

1、浏览器支持情况检测

检测浏览器支持情况代码   收藏代码
  1. function loadDemo() {  
  2.     if (window.WebSocket) {  
  3.         //supported  
  4.     } else {  
  5.         // not supported  
  6.     }  
  7. }  

2、WebSocket对象的创建和服务器连接

要连接通信端点,只需要创建一个新的WebSocket实例,并提供希望连接的对端URL。ws://和wss://前缀分别表示WebSocket连接和安全的WebSocket连接。

Js代码   收藏代码
  1. url = "ws://localhost:8080/echo";  
  2. w = new WebSocket(url);  

 

建立WebSocket连接时,可以列出Web应用能够使用的协议。WebSocket构造函数的第二个参数既可以是字符串,也可以是字符串组。

Js代码   收藏代码
  1. w = new WebSocket(url, ["proto1""proto2"]);  

假设proto1和proto2是定义明确、可能已注册且标准化的协议名称,它们能够同时为客户端和服务器端所理解。服务器会从列表中选择首选协议。

Js代码   收藏代码
  1. onopen = function(e) {  
  2.     //确定服务器选择的协议  
  3.     log(e.target.protocol);  
  4. }  

 

3、添加事件监听器

WebSocket编程遵循异步编程模型;打开socket后,只需等待事件发生,而不需要主动向服务器轮询,所以需要在WebSocket对象中添加回调函数来监听事件。

WebSocket对象有三个事件:open、close和message。

Js代码   收藏代码
  1. w.onopen = function() {  
  2.     log("open");  
  3.     w.send("send message");  
  4. }  
  5. w.onmessage = function(e) {  
  6.     log(e.data);  
  7. }  
  8. w.onclose = function(e) {  
  9.     log("closed");  
  10. }  
  11. w.onerror = function(e) {  
  12.     log("error");  
  13. }  

 

4、发送消息

当socket处于打开状态(即onopen之后,onclose之前),可以用send方法来发送消息。消息发送完,可以调用close方法来终止连接,也可以不这么做,让其保持打开状态。

Js代码   收藏代码
  1. w.send();  

 

你可能想测算在调用Send()函数之前,有多少数据备份在发送缓冲区中。bufferAmount属性表示已在WebSocket上发送但尚未写入网络的字节数。它对于调节发送速率很有用。

Js代码   收藏代码
  1. document.getElementById("sendButton").onclick = function() {  
  2.     if (w.bufferedAmount < bufferThreshold) {  
  3.         w.send(document.getElementById("inputMessage").value);  
  4.     }  
  5. }  

WebSocket API支持以二进制数据的形式发送Blob和ArrayBuffer实例

Js代码   收藏代码
  1. var a = new Uint8Array([8, 6, 7, 5, 3, 0, 9]);  
  2. w.send(a.buffer);  

 

三、例子

书中介绍了一个用Python写的Echo服务,书中的代码可以在http://www.apress.com/9781430238645 的“Source Code/Downloads”中下载下载。

对于JAVA开发人员Tomcat是最熟悉的,在Tomcat8中已经实现了WebSocket API 1.0。Tomcat7也会在不久实现(现在的实现不是WebSocket API 1.0)。

在这里写一下在Tomcat8下执行的例子。

例子由客户端页面和WebSocket服务程序组成,功能在Echo基础上增加一个服务端定时发送信息的功能。

 

页面程序 ws.html代码   收藏代码
  1.   
  2.   
  3.   
  4. "UTF-8">  
  5. Test WebSocket  
  6. "text/javascript">  
  7.     //显示信息  
  8.     var log = function(s) {  
  9.         if (document.readyState !== "complete") {  
  10.             log.buffer.push(s);  
  11.         } else {  
  12.             document.getElementById("output").textContent += (s + "\n");  
  13.             document.getElementById("outputdiv").scrollTop = document.getElementById("outputdiv").scrollHeight;  
  14.         }  
  15.     }  
  16.     log.buffer = [];  
  17.     //显示连接状态  
  18.     function setConnected(status) {  
  19.         document.getElementById("socketstatus").innerHTML = status;  
  20.     }  
  21.     var ws = null;  
  22.       
  23.     //连接  
  24.     function connect() {  
  25.         if (ws != null) {  
  26.             log("现已连接");  
  27.             return ;  
  28.         }  
  29.         url = "ws://localhost:8080/websocket/mywebsocket";  
  30.         if ('WebSocket' in window) {  
  31.             ws = new WebSocket(url);  
  32.         } else if ('MozWebSocket' in window) {  
  33.             ws = new MozWebSocket(url);  
  34.         } else {  
  35.             alert("您的浏览器不支持WebSocket。");  
  36.             return ;  
  37.         }  
  38.         ws.onopen = function() {  
  39.             log("open");  
  40.             setConnected("已连接");  
  41.             //设置发信息送类型为:ArrayBuffer  
  42.             ws.binaryType = "arraybuffer";  
  43.               
  44.             //发送一个字符串和一个二进制信息  
  45.             ws.send("thank you for accepting this WebSocket request");  
  46.             var a = new Uint8Array([8675309]);  
  47.             ws.send(a.buffer);  
  48.         }  
  49.         ws.onmessage = function(e) {  
  50.             log(e.data.toString());  
  51.         }  
  52.         ws.onclose = function(e) {  
  53.             log("closed");  
  54.         }  
  55.         ws.onerror = function(e) {  
  56.             log("error");  
  57.         }  
  58.     }  
  59.       
  60.     //断开连接  
  61.     function disconnect() {  
  62.         if (ws != null) {  
  63.             ws.close();  
  64.             ws = null;  
  65.             setConnected("已断开");  
  66.         }  
  67.     }  
  68.       
  69.     window.onload = function() {  
  70.         connect();  
  71.         log(log.buffer.join("\n"));  
  72.         //发送页面上输入框的信息  
  73.         document.getElementById("sendButton").onclick = function() {  
  74.             if (ws != null) {  
  75.                 ws.send(document.getElementById("inputMessage").value);   
  76.             }  
  77.         }  
  78.         //停止心跳信息  
  79.         document.getElementById("stopButton").onclick = function() {  
  80.             if (ws != null) {  
  81.                 var a = new Uint8Array([19201516]);  
  82.                 ws.send(a.buffer);   
  83.             }  
  84.         }  
  85.     }  
  86.   
  87.   
  88. "disconnect();">  
  89.     
    连接状态:"socketstatus">
      
  90.     
      
  91.         "text" id="inputMessage" value="Hello, WebSocket!">  
  92.         "sendButton">发送"stopButton" style="margin-left:15px">停止心跳信息  
  93.     
  
  •     
      
  •         "connect" οnclick="connect();">连接  
  •         "disconnect" οnclick="disconnect();">断开  
  •     
  •   
  •     "height:300px; overflow:auto;" id="outputdiv">  
  •         "output">  
  •     
  •   
  •   
  •   
  •  

    服务端程序用注解方式驱动

     

    Websocket服务端程序代码   收藏代码
    1. package com.test.wsocket;  
    2.   
    3. import java.io.IOException;  
    4. import java.nio.ByteBuffer;  
    5. import java.util.Random;  
    6. import java.util.Timer;  
    7. import java.util.TimerTask;  
    8.   
    9. import javax.websocket.OnClose;  
    10. import javax.websocket.OnMessage;  
    11. import javax.websocket.OnOpen;  
    12. import javax.websocket.PongMessage;  
    13. import javax.websocket.Session;  
    14. import javax.websocket.server.ServerEndpoint;  
    15.   
    16. @ServerEndpoint("/mywebsocket")  
    17. public class MyWebSocket {  
    18.       
    19.     private Session session;  
    20.     private static final Random random = new Random();  
    21.     private Timer timer = null;  
    22.     //停止信息信息指令  
    23.     private static final ByteBuffer stopbuffer  = ByteBuffer.wrap(new byte[]{19201516});  
    24.       
    25.     /**  
    26.      * 打开连接时执行  
    27.      * @param session  
    28.      */  
    29.     @OnOpen  
    30.     public void start(Session session) {  
    31.         this.session = session;  
    32.         try {  
    33.             System.out.println("open");  
    34.             if (session.isOpen()) {  
    35.                 //设置心跳发送信息。每2秒发送一次信息。  
    36.                 timer = new Timer(true);  
    37.                 timer.schedule(task, 10002000);  
    38.             }  
    39.         } catch (Exception e) {  
    40.             try {  
    41.                 session.close();  
    42.             } catch (IOException e1) {}  
    43.         }  
    44.     }  
    45.   
    46.     /**  
    47.      * 接收信息时执行  
    48.      * @param session  
    49.      * @param msg 字符串信息  
    50.      * @param last  
    51.      */  
    52.     @OnMessage  
    53.     public void echoTextMessage(Session session, String msg, boolean last) {  
    54.         try {  
    55.             if (session.isOpen()) {  
    56.                 System.out.println("string:" + msg);  
    57.                 session.getBasicRemote().sendText(msg, last);  
    58.             }  
    59.         } catch (IOException e) {  
    60.             try {  
    61.                 session.close();  
    62.             } catch (IOException e1) {  
    63.                 // Ignore  
    64.             }  
    65.         }  
    66.     }  
    67.   
    68.     /**  
    69.      * 接收信息时执行  
    70.      * @param session  
    71.      * @param bb 二进制数组  
    72.      * @param last  
    73.      */  
    74.     @OnMessage  
    75.     public void echoBinaryMessage(Session session, ByteBuffer bb, boolean last) {  
    76.         try {  
    77.             if (session.isOpen()) {  
    78.                 //如果是停止心跳指令,则停止心跳信息  
    79.                 if (bb.compareTo(stopbuffer) == 0) {  
    80.                     if (timer != null) {  
    81.                         timer.cancel();  
    82.                     }  
    83.                 } else {  
    84.                     session.getBasicRemote().sendBinary(bb, last);  
    85.                 }  
    86.             }  
    87.         } catch (IOException e) {  
    88.             try {  
    89.                 session.close();  
    90.             } catch (IOException e1) {  
    91.                 // Ignore  
    92.             }  
    93.         }  
    94.     }  
    95.       
    96.     /**  
    97.      * 接收pong指令时执行。  
    98.      *  
    99.      * @param pm    Ignored.  
    100.      */  
    101.     @OnMessage  
    102.     public void echoPongMessage(PongMessage pm) {  
    103.         // 无处理  
    104.     }  
    105.       
    106.     @OnClose  
    107.     public void end(Session session) {  
    108.         try {  
    109.             System.out.println("close");  
    110.             if (timer != null) {  
    111.                 timer.cancel();  
    112.             }  
    113.         } catch(Exception e) {  
    114.         }  
    115.     }  
    116.       
    117.     /*  
    118.      * 发送心跳信息  
    119.      */  
    120.     public void sendLong(long param) {  
    121.         try {  
    122.             if (session.isOpen()) {  
    123.                 this.session.getBasicRemote().sendText(String.valueOf(param));  
    124.             }  
    125.         } catch (IOException e) {  
    126.             try {  
    127.                 this.session.close();  
    128.             } catch (IOException e1) {}  
    129.         }  
    130.     }  
    131.       
    132.     /**  
    133.      * 心跳任务。发送随机数。  
    134.      */  
    135.     TimerTask task = new TimerTask() {  
    136.         public void run() {     
    137.             long param = random.nextInt(100);  
    138.             sendLong(param);  
    139.         }     
    140.     };  
    141.   
    142. }  

     

     

    Web.xml代码   收藏代码
    1. "1.0" encoding="UTF-8"?>  
    2. "http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">  
    3.   websocket  
    4.     
    5.     index.html  
    6.     
    7.     
    8.     
    9.         Set Character Encoding  
    10.         org.apache.catalina.filters.SetCharacterEncodingFilter  
    11.           
    12.             encoding  
    13.             UTF-8  
    14.           
    15.           
    16.             ignore  
    17.             true  
    18.           
    19.       
    20.       
    21.       
    22.         Set Character Encoding  
    23.         /*  
    24.       
    25.   

     

    将以上程序部署到Tomcat8下,启动服务。


    WebSocket使用_第1张图片

    你可能感兴趣的:(综合)