• 选学校
  • 高中毕后选择什么学校好
  • 启蒙星
  • 株洲北大青鸟校区升级

您现在的位置:株洲北大青鸟 >> >> 师资力量>> 技术天地

师资力量
开班信息
输入姓名手机号码预约试听课程
姓  名:*
手机号:*
创业摇篮班
开班日期:本月
招生人数:已满
就业直通班
开班日期:本月
招生人数:招生中
就业精英班
开班日期:本月
招生人数:25
技术天地
  • 轻松掌握WebSocket技术
  • 〖不上名牌大学,就读株洲北大青鸟〗 发布人:株洲北大青鸟
  • 发表日期:2018/4/20 11:08:36 阅读数:2  
  •  
  • 引言

    “盛哥,我们公司需要完成一个类似淘宝网的在线客服APP?”,“盛哥,我们公司的xx系统需要增加一个消息广播功能,如何实现啊,头大啊,救命啊!”,“消息推送如何实现啊......”。

     

    以上信息来至于毕业学员对我的技术反馈,从中我找到了一些技术关键词,毕竟是搞技术出生的哦。例如:在线客服,消息推送,WebIM等。在H5技术没有来临的时代,那些功能实现起来确实非常麻烦,而且安全性能也非常低。自从有了H5技术以后大神们再也不用担心碰壁了,谁用谁爽。而这个技术神器就是我们今天的主角“WebSocket”,即Realtime技术。

     

    一、揭开WebSocket技术神秘的面纱

    WebSocket本质上是一个基于TCP的协议,在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。它由通信协议和编程API组成,WebSocket能够在浏览器和服务器之间建立双向连接,以基于事件的方式,赋予浏览器实时通信能力。既然是双向通信,就意味着服务器端和客户端可以同时发送并响应请求,而不再像HTTP的请求和响应。广泛应用于Web的实时消息推送领域,这种技术要达到的目的是让用户不需要刷新浏览器就可以获得实时更新。它有着广泛的应用场景,比如在线聊天室、在线客服系统、评论系统、WebIM等。

     

    初次接触 WebSocket 的人,都会问同样的问题:我们已经有了 HTTP 协议,为什么还需要另一个协议?它能带来什么好处?

     

    答案很简单,因为 HTTP 协议有一个缺陷:通信只能由客户端发起。

     

    举例来说,我们想了解今天的天气,只能是客户端向服务器发出请求,服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。

     

     

     

    这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。我们只能使用"轮询":每隔一段时候,就发出一个询问,了解服务器有没有新的信息。最典型的场景就是聊天室。

     

    轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。因此,工程师们一直在思考,有没有更好的方法。WebSocket 就是这样发明的。

     

    WebSocket 它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

     

     

    其他特点包括:

     

    (1)建立在 TCP 协议之上,服务器端的实现比较容易。

     

    (2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

     

    (3)数据格式比较轻量,性能开销小,通信高效。

     

    (4)可以发送文本,也可以发送二进制数据。

     

    (5)没有同源限制,客户端可以与任意服务器通信。

     

    (6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

     

     ws://192.168.183.1:8080/accp/showws

     

     

     

     

    二、轻松掌握基于WebSocket协议编程

    我们基于WebSocket协议的编程,必须要掌握两端Socket的应用开发,即客服端Socket与服务器端Socket。

    2.1 客户端Socket实现

      客户端Socket通讯主要依赖H5中的WebSocket对象来完成,奉上一段js代码,童靴们一看便知,有点像ajax中XMLHttpRequest对象操作:

    var ws = new WebSocket("ws://192.168.183.1:8080/accp/showws");

    ws.onopen = function(evt) {

      console.log("打开连接");

      ws.send("Hello Accp!");

    };

    ws.onmessage = function(evt) {

      console.log( "接收服务器消息: " + evt.data);

      ws.close();

    };

    ws.onclose = function(evt) {

      console.log("关闭连接");

    };

     

     

    WebSocket对象常用API如下:

     

     

     

     

     

    2.1.1 WebSocket 构造函数

     

    WebSocket 对象作为一个构造函数,用于新建 WebSocket 实例。

    var ws = new WebSocket('ws://192.168.183.1:8080/accp/showws');

     

    执行上面语句之后,客户端就会与服务器进行连接。实例对象的所有属性和方法清单,参见上面的图。

     

    2.2.2 WebSocket.readyState

     

    readyState属性返回实例对象的当前状态,共有四种:

    CONNECTING:值为0,表示正在连接。

    OPEN:值为1,表示连接成功,可以通信了。

    CLOSING:值为2,表示连接正在关闭。

    CLOSED:值为3,表示连接已经关闭,或者打开连接失败。

    下面是一个示例:

    switch (ws.readyState) {

      case WebSocket.CONNECTING:   

        break;

      case WebSocket.OPEN:

        break;

      case WebSocket.CLOSING:

        break;

      case WebSocket.CLOSED:

        break;

      default:   

    break;

    }

     

     

    2.1.3 webSocket.onopen

     

    实例对象的onopen属性,用于指定连接成功后的回调函数。

    ws.onopen = function () {

      ws.send('Hello Accp!');

    }

     

     

    如果要指定多个回调函数,可以使用addEventListener方法。

    ws.addEventListener('open', function (event) {

      ws.send('Hello Accp!');

    });

     

     

    2.1.4 webSocket.onclose

     

    实例对象的onclose属性,用于指定连接关闭后的回调函数。

    ws.onclose = function(event) {

      var code = event.code;

      var reason = event.reason;

      var wasClean = event.wasClean;

     };

     

     

    2.1.5 webSocket.onmessage

     

     

    实例对象的onmessage属性,用于指定收到服务器数据后的回调函数。

     

     

     

     

    ws.onmessage = function(event) {

      var data = event.data;

      // 处理数据

    };

     

    注意,服务器数据可能是文本,也可能是二进制数据(blob对象或Arraybuffer对象)。

    ws.onmessage = function(event){

      if(typeof event.data === String) {

        console.log("Received data string");

      }

      else if(event.data instanceof ArrayBuffer){

        var buffer = event.data;

        console.log("Received arraybuffer");

      }

    }

     

    除了动态判断收到的数据类型,也可以使用binaryType属性,显式指定收到的二进制数据类型。

    // 收到的是 blob 数据

    ws.binaryType = "blob";

    ws.onmessage = function(e) {

      console.log(e.data.size);

     

    };

    // 收到的是 ArrayBuffer 数据

    ws.binaryType = "arraybuffer";

    ws.onmessage = function(e) {

      console.log(e.data.byteLength);

    };

     

     

     

     

    2.1.6 webSocket.send()

     

    实例对象的send()方法用于向服务器发送数据。

     

    ws.onmessage = function(event){

      ws.send('发送数据给服务器socket');

      var file = document .querySelector('input[type="file"]').files[0];

      ws.send(file);

      var img = canvas_context.getImageData(0, 0, 400, 320);

      var binary = new Uint8Array(img.data.length);

      for (var i = 0; i < img.data.length; i++) {

        binary[i] = img.data[i];

      }

      ws.send(binary.buffer);

    }

     

     

     

    2.1.7  webSocket.bufferedAmount

     

    实例对象的bufferedAmount属性,表示还有多少字节的二进制数据没有发送出去。它可以用来判断发送是否结束。

    var data = new ArrayBuffer(10000000);

    wst.send(data);

    if (ws.bufferedAmount === 0) {

      // 发送完毕

    } else {

      // 发送还没结束

    }

     

     

     

     

     

    2.1.8 webSocket.onerror

    实例对象的onerror属性,用于指定报错时的回调函数。

     

    ws.onerror = function(event) {

      // 错误处理代码

    };

     

     

     

     

     

    2.2 服务器Socket实现

    WebSocket 服务器的实现,可以查看维基百科的列表,常用的 Node 实现有以下三种:

    l WebSockets

    l Socket.IO

    l WebSocket-Node

    具体的用法请查看它们的文档,这里不详细介绍了。今天我主要讲解如何使用Java中的SpringSocket进行通讯交互。基于maven的Spring环境搭建在这里就不做讲解了,重点讲解WebSocket配置。首先通过maven依赖两个jar,分别如下:

    <dependency>

    <groupId>org.springframework</groupId>

    <artifactId>spring-websocket</artifactId>

        <version>4.3.9</version>

    </dependency>

    <dependency>

    <groupId>org.springframework</groupId>

    <artifactId>spring-messaging</artifactId>

        <version>4.3.9</version>

    </dependency>

     

     

     

     

    2.2.1 继承TextWebSocketHandler类

    自定义一个消息处理类MessageHandler继承TextWebSocketHandler类用来处理文本消息,类似于Servlet编程,如下:

     

     

     

     

    2.2.2 在Spring主配置文件部署WebSocket消息处理服务

    核心配置如下:

    <bean id="msgWs" class="com.accp.webhandler.MessageHandler"/>

    <websocket:handlers>

    <websocket:mapping handler="msgWs" path="/showws"/>

    </websocket:handlers>

     

     

    童靴们还记得前面客服端Socket实现中的这段代码吗?

    var ws = new WebSocket('ws://192.168.183.1:8080/accp/showws');

    没有错客户端Socket就与服务器Socket(MessageHandler)建立连接,会相应调用其方法处理消息,有点类似于Servlet处理Http请求/响应的方式.

    小结:

    到此WebSocket开发步骤就讲解完毕了,下面我用一个思维导图给大家回顾一下:

     

     

     

    三、WebSocket技术干货案例

    通过以上开发步骤的讲解大家对WebSocket基本有所了解,但是实际项目中怎么用?到底用在哪里?相信还是一头雾水。接下来我就奉上一个非常简单的基于SSM架构通告消息广播完整案例给大家。众所周知发布消息是每个MIS系统必备的功能,后台管理员发布消息通告,前台用户在消息页面接收消息通告。早期web1.0的技术实现都需要前台用户不停的刷新页面来获得最新消息,这样的体验是非常差的。后来web2.0中的ajax技术解决了刷新问题,采用轮询策略改善了用户体验,可惜性能太差始终是个大坑,为此很多大神陷入此坑不能自拔。今天我们就用WebSocket技术神器完美兼顾体验和性能。

     

    3.1 服务器端WebSocket消息处理类Handler

    public class MessageHandler extends TextWebSocketHandler {

    private final static List<WebSocketSession> users = new ArrayList<WebSocketSession>();// 存放连接的用户信息缓存,推荐使用Map集合

    @Override

    public void afterConnectionEstablished(WebSocketSession session) throws Exception {

    users.add(session);// 往缓存中加入连接的用户信息

    }

    @Override

    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {

    users.remove(session);// 从缓存中移除连接的用户信息

    }

    @Override

    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {

    if (session.isOpen()) {

    users.remove(session);

    session.close();

    }

    }

     

    /**

     *

     * @title: sendMessageToAllUsers

     * @description: 给所有用户发送消息

     * @param msg

     * @throws Exception

     */

    public void sendMessageToAllUsers(String msgTxt) {

    for (WebSocketSession user : users) {

    try {

    user.sendMessage(new TextMessage(msgTxt));// 给用户发送消息文本

    } catch (Exception ex) {

    continue;

    }

    }

    }

     

    }

     

    3.2 服务器端Http请求/响应处理类Controller

    服务器端处理新增消息的请求,其中Biz,Dao,Entity的操作代码就省略了。重点是在新增消息成功后,通过消息处理类给所有用户群发"reloadMsgList"消息来通知客户端自动刷新消息数据列表。

    @RestController

    @RequestMapping("/")

    public class WebMessageAction {

     

    @Autowired

    private WebMessageBiz messageBiz;

     

    @Autowired

    private MessageHandler messageHandler;//注入消息处理类

     

    @RequestMapping("list")

    public List<WebMessage> getMessageList() throws Exception {

    return messageBiz.findMessageList();

    }

     

    @RequestMapping("add")

    public Map<String, String> addMessage(@RequestBody WebMessage message) throws Exception {

    Map<String, String> map = new HashMap<String, String>();

    messageBiz.addMessage(message);

    map.put("code", "200");

    map.put("msg", "ok");

    messageHandler.sendMessageToAllUsers("reloadMsgList");//广播通知所有建立WebSocket连接的用户

    return map;

     

    }

    }

     

     

    3.3 Spring相关配置spring-mvc.xml

    <?xml version="1.0" encoding="UTF-8"?>

     

    <beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"

    xmlns:context="http://www.springframework.org/schema/context"

    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:websocket="http://www.springframework.org/schema/websocket"

    xsi:schemaLocation="

    http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans-4.3.xsd

    http://www.springframework.org/schema/context

    http://www.springframework.org/schema/context/spring-context-4.3.xsd

    http://www.springframework.org/schema/mvc

    http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd

    http://www.springframework.org/schema/websocket

    http://www.springframework.org/schema/websocket/spring-websocket.xsd

    ">

    <import resource="spring-ctx.xml" />

    <context:component-scan base-package="com.accp.mis.action"

    use-default-filters="true" />

    <mvc:default-servlet-handler />

    <mvc:annotation-driven>

    <mvc:message-converters register-defaults="true">

    <bean

    class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">

    <property name="supportedMediaTypes">

    <list>

    <value>application/json;charset=UTF-8</value>

    </list>

    </property>

    <property name="features">

    <list>

    <value>WriteMapNullValue</value>

    <value>WriteNullNumberAsZero</value>

    <value>WriteNullStringAsEmpty</value>

    <value>WriteDateUseDateFormat</value>

    <value>WriteEnumUsingToString</value>

    <value>QuoteFieldNames</value>

    </list>

    </property>

    </bean>

    </mvc:message-converters>

    </mvc:annotation-driven>

    <bean id="msgWs" class="com.accp.webhandler.MessageHandler"/>

    <websocket:handlers>

    <websocket:mapping handler="msgWs" path="/msgws"/>

    </websocket:handlers>

    </beans>

     

    3.4 客户端页面实现View

    <!DOCTYPE html>

    <html>

    <head>

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

    <style type="text/css">

    .box {

    -webkit-animation: playBox 1.0s infinite;

    }

     

    @

    -webkit-keyframes playBox { 0%{

    text-decoration: none;

    color: #red;

    }

    50%{

    text-decoration

    :none

    ;

     

    color

    :

    #ffdcdc

    ;

    }

    51%{

    text-decoration

    :none

    ;

     

    color

    :

    #e9c8c8

    ;

    }

    100%{

    text-decoration

    :none

    ;

     

    color

    :

    #e9c8c8

    ;

    }

    }

    </style>

    </head>

    <body>

    <div id="showNewMsg" style="display: none;">

    <h4 class="box" style="color: red">您有新消息</h4>

    </div>

    <table border="1" width="500">

    <thead>

    <tr style="background-color: #EFEFEF">

    <th>序号</th>

    <th>消息主题</th>

    <th>发布者</th>

    <th>发布时间</th>

    </tr>

    </thead>

    <tbody id="cnt">

     

    </tbody>

    </table>

    </body>

    <script type="text/javascript" src="js/jquery-1.12.4.js"></script>

    <script type="text/javascript">

    if (window.WebSocket) {

    var ws = new WebSocket("ws://192.168.183.1:8080/webmessage/msgws");

    ws.onpen = function(e) {

    console.log('打开连接');

    }

    ws.onclose = function(e) {

    console.log('关闭连接');

    }

    ws.onerror = function(e) {

    console.log('传输错误');

    ws.close();

    }

    ws.onmessage = function(e) {

    $("#showNewMsg").show();

          var msgTxt=e.data;

          if(msgTxt=="reloadMsgList"){

            window.setTimeout(function(){

          loadMessageList();

          $("#showNewMsg").hide();

          }, 3000);

          }

          }

     

    } else {

    alert("不支持WebSocket技术");

     

    }

     

    //加载消息列表

    function loadMessageList() {

    $.ajax("list", {

    type : "GET",

    dataType : "json",

    timeout : 5000,

    success : function(list) {

    $("#cnt").empty();

    $.each(list, function(i, item) {

    $("#cnt").append(

    "<tr><td>" + (i + 1) + "</td><td>" + item.mtitle

    + "</td><td>" + item.muser + "</td><td>"

    + item.mdate + "</td></tr>");

    });

    }

    });

    }

    loadMessageList();

    </script>

     

    </html>

     

     

    四、使用心得与经验分享

    相信童靴们认真看完且实操了以上步骤后,基本对WebSocket技术的掌握已经达到入门级,慢慢也能理解WebsScket协议相比Http协议上的性能优势.当然它不完美也存在一些缺点,比如:它不支持Cookie技术,对开发者要求高了许多,对前端开发者,往往要具备数据驱动使用javascript的能力,且需要维持住ws连接(否则消息无法推送);对后端开发者而言,难度增大了很多,一是长连接需要后端处理业务的代码更稳定(不要随便把进程和框架都crash掉),二是推送消息相对复杂一些,三是成熟的http生态下有大量的组件可以复用,WebSocke组件相对少很多等等。那么到底什么类型的应用合适使用WebSocket,能用就用,能不用就不用,扬长避短了?吃瓜群众们往下看。。。

     

    1.社交订阅

     

    对社交类的应用的一个裨益之处就是能够即时的知道你的朋友正在做什么。虽然听起来有点可怕,但是我们都喜欢这样做。你不会想要在数分钟之后才能知道一个家庭成员在馅饼制作大赛获胜或者一个朋友订婚的消息。你是在线的,所以你的订阅的更新应该是实时的。

     

    2.多玩家游戏

     

    网络正在迅速转变为游戏平台。在不使用插件(我指的是Flash)的情况下,网络开发者现在可以在浏览器中实现和体验高性能的游戏。无论你是在处理DOM元素、CSS动画,HTML5的canvas或者尝试使用WebGL,玩家之间的互动效率是至关重要的。我不想在我扣动扳机之后,我的对手却已经移动位置。

     

    3.协同编辑/编程

     

    我们生活在分布式开发团队的时代。平时使用一个文档的副本就满足工作需求了,但是你最终需要有一个方式来合并所有的编辑副本。版本控制系统,比如Git能够帮助处理某些文件,但是当git发现一个它不能解决的冲突时,你仍然需要去跟踪人们的修改历史。通过一个协同解决方案,比如WebSocket,我们能够工作在同一个文档,从而省去所有的合并版本。这样会很容易看出谁在编辑什么或者你在和谁同时在修改文档的同一部分。

     

    4.点击流数据

     

    分析用户与你网站的互动是提升你的网站的关键。HTTP的开销让我们只能优先考虑和收集最重要的数据部分。然后,经过六个月的线下分析,我们意识到我们应该收集一个不同的判断标准——一个看起来不是那么重要但是现在却影响了一个关键的决定。与HTTP请求的开销方式相比,使用Websocket,你可以由客户端发送不受限制的数据。想要在除页面加载之外跟踪鼠标的移动?只需要通过WebSocket连接发送这些数据到服务器,并存储在你喜欢的NoSQL数据库中就可以了(MongoDB是适合记录这样的事件的)。现在你可以通过回放用户在页面的动作来清楚的知道发生了什么。

     

    5.股票基金报价

     

    金融界瞬息万变——几乎是每毫秒都在变化。我们人类的大脑不能持续以那样的速度处理那么多的数据,所以我们写了一些算法来帮我们处理这些事情。虽然你不一定是在处理高频的交易,但是,过时的信息也只能导致损失。当你有一个显示盘来跟踪你感兴趣的公司时,你肯定想要随时知道他们的价值,而不是10秒前的数据。使用WebSocket可以流式更新这些数据变化而不需要等待。

     

    6.体育实况更新

     

    现在我们开始讨论一个让人们激情澎湃的愚蠢的东西——体育。我不是运动爱好者,但是我知道运动迷们想要什么。当爱国者在打比赛的时候,我的妹夫将会沉浸于这场比赛中而不能自拔。那是一种疯狂痴迷的状态,完全发自内心的。我虽然不理解这个,但是我敬佩他们与运动之间的这种强烈的联系,所以,最后我能做的就是给他的体验中降低延迟。如果你在你的网站应用中包含了体育新闻,WebSocket能够助力你的用户获得实时的更新。

     

    7.基于位置的应用

     

    越来越多的开发者借用移动设备的GPS功能来实现他们基于位置的网络应用。如果你一直记录用户的位置(比如运行应用来记录运动轨迹),你可以收集到更加细致化的数据。如果你想实时的更新网络数据仪表盘(可以说是一个监视运动员的教练),HTTP协议显得有些笨拙。借用WebSocket TCP链接可以让数据飞起来。

     

     

上一篇:Java JDK 10:下一代 Java 有哪些新特性?
分享到:

版权所有 ©株洲健坤科技职业培训学校    学校地址:株洲市天元区黄山路205号健坤大厦(天元区消防中队对面)

咨询报名热线:400-8812-866    邮箱地址:4008812866@b.qq.com   备案号: 湘ICP备10202015号  

北大青鸟学费是多少 湖南北大青鸟怎么样
株洲北大青鸟好不好 株洲北大青鸟学费多少 株洲北大青鸟学校这么样