zoukankan      html  css  js  c++  java
  • websocket介绍

    一,Websocket是什么?

    Websocket是一个因为应用场景越来越复杂而提出的,针对浏览器和web服务器之间双向持续通信而设计,而且优雅地兼容HTTP的协议。

    WebSocket 实际上指的是一种协议,与我们熟知的Http协议是同等的一个网络协议。用网络模型结构来解释的话,WebSocket和Http协议都属于应用层协议,两者都基于传输层的TCP协议。
    websocket协议本质上是一个基于tcp的协议,是先通过HTTP/HTTPS协议发起一条特殊的http请求进行握手后创建一个用于交换数据的TCP连接,此后服务端与客户端通过此TCP连接进行实时通信。

    注:websocket与http协议的关系

    WebSocket不是Http协议,Http协议只是被WebSocket使用来建立连接,连接建立了以后客户端与服务器的双向通信就与Http无关了。
    借用了http的协议完成握手的一个新协议,可以说是基于http协议,可以说是http协议的一种补充,也可以说与http协议毫无关系。

    二, Websocket的作用和优点?

    1,非WebSocket的实时信息传递技术

    轮询:

    轮询是由客户端定时向服务端发起查询数据的请求的一种实现方式。早期的轮询是通过不断自动刷新页面而实现的。
    在特定的时间间隔(例如1秒),由浏览器向服务器发出一个Http Request,然后服务器返回最新的数据给客户端浏览器,从而给出一种服务端实时推送的假象。由于Http Request的Header(请求头)很长,而传输的数据可能很短就只占一点点,每次请求消耗的带宽和服务器资源大部分都消耗在Header上。(想想ajax技术和全页面传值的资源消耗)

    ajax轮询:

    ajax轮询,又被称为Comet,由客户端不停地请求服务器端,查询有没有新消息,然后再由服务器返回结果;是轮询的一种优化,实现了无刷新更新数据,并且不用传递header头的信息,传递内容更少。
    
    但本质上这些方式均是客户端定时轮询服务端,这种方式的最显著的缺点是如果客户端数量庞大并且定时轮询间隔较短服务端将承受响应这些客户端海量请求的巨大的压力。

    长轮询:

    长轮询(long polling)是另一种流行的通信方法,客户端向服务器请求信息,并在设定的时间段内打开一个连接。服务器如果没有任何信息,会保持请求打开,直到有客户端可用的信息,或者直到指定的超时时间用完为止。这时,客户端重新向服务器请求信息。长轮询也称作Comet(前面已经提到过)或者反向AJAX。Comet延长HTTP响应的完成,直到服务器有需要发送给客户端的内容,这种技术常常称作“挂起GET”或“搁置POST”。重要的是要知道,当信息量很大时,长轮询相对于传统轮询并没有明显的性能优势,因为客户端必须频繁地重连到服务器以读取新信息,造成网络的表现和快速轮询相同。长轮询的另一个问题是缺乏标准实现。
    
    长轮询其实原理跟ajax轮询差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直打电话,没收到就不挂电话),也就是说,通过一次请求,询问服务器有没有新消息更新,如果没有新消息时,会保持长连接,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。
    
    在数据更新不够频繁的情况下,使用轮询方法获取数据时客户端经常会得到没有数据的响应,显然这样的轮询是一个浪费网络资源的无效的轮询。长轮询则是针对普通轮询的这种缺陷的一种改进方案,其具体实现方式是如果当前请求没有数据可以返回,则继续保持当前请求的网络连接状态,直到服务端有数据可以返回或者连接超时。长轮询通过这种方式减少了客户端与服务端交互的次数,避免了一些无谓的网络连接。但是如果数据变更较为频繁,则长轮询方式与普通轮询在性能上并无显著差异。同时,增加连接的等待时间,往往意味着并发性能的下降。
    
    长轮询虽然降低了服务器的负载,但是需要服务器有很高的并发能力才可以。
    而目前处理高并发的模型基本都是异步非阻塞的模型(比如nginx)。
    既想阻塞,又想高并发,几乎不可能。
    

    流:

    所谓流是指客户端在页面之下向服务端发起一个长连接请求,服务端收到这个请求后响应它并不断更新连接状态,以确保这个连接在客户端与服务端之间一直有效。服务端可以通过这个连接将数据主动推送到客户端。显然,这种方案实现起来相对比较麻烦,而且可能被防火墙阻断。
    
    在流化技术中,客户端发送一个请求,服务器发送并维护一个持续更新和保持打开(可以是无限或者规定的时间段)的开放响应。每当服务器有需要交付给客户端的信息时,它就更新响应。看起来,流化是能够适应不可预测的信息交付的极佳方案,但是服务器从不发出完成HTTP响应的请求,从而使连接一直保持打开。在这种情况下,代理和防火墙可能缓存响应,导致信息交付的延迟增加。因此,许多流化的尝试对于存在防火墙和代理的网络是不友好的。
    
    流技术方案通常就是在客户端的页面使用一个隐藏的窗口向服务端发出一个长连接的请求。服务器端接到这个请求后作出回应并不断更新连接状态以保证客户端和服务器端的连接不过期。通过这种机制可以将服务器端的信息源源不断地推向客户端。这种机制在用户体验上有一点问题,需要针对不同的浏览器设计不同的方案来改进用户体验,同时这种机制在并发比较大的情况下,对服务器端的资源是一个极大的考验。

    2,传统方法的缺点

    上述方法提供了近乎实时的通信,
    但是它们也涉及HTTP请求和响应首标,
    包含了许多附加和不必要的首标数据与延迟。
    
    此外,在每一种情况下,客户端都必须等待请求返回,才能发出后续的请求,而这显著地增加了延迟。
    
    以上四种方法的后三种呢,都实现了真正的双工通信,但都是单向链接,需要被动的请求服务器,而不是由服务器自动发给客户端。(还是在代码层面上下功夫,但是这种情况下,明显需要从协议层去想办法)
    
    首先就是非常消耗资源,不断地建立HTTP连接,然后等待服务端处理,可以体现HTTP协议的另外一个特点,被动性。其次呢,
    ajax轮询需要服务器有很快的处理速度和资源,
    长轮询需要有很高的并发,也就是同时处理请求的能力

    3,Websocket的优点

    基于此,websocket出现了,它解决了http不利于这种场景下(聊天,视频...)的两个问题:
    http协议是一个无状态的,被动的协议(不持久,服务端无法主动发送信息给客户端)
    
    Websocket只需要一次HTTP握手,所以说整个通讯过程是建立在一次连接/状态中,也就避免了HTTP的非状态性,服务端会一直知道你的信息,直到你关闭请求,这样就解决了接线员要反复解析HTTP协议,
    还要查看identity info的信息。 同时由客户主动询问,转换为服务器(推送)有信息的时候就发送(当然客户端还是等主动发送信息过来的。。),没有信息的时候就交给接线员(Nginx),不需要占用本身速度就慢的客服(Handler)了 所以 Websocket能更好的实现双向通信且节省服务器资源和带宽。

    三,websocket协议解析

    wensocket协议包含两部分:一部分是“握手”,一部分是“数据传输”

    ①客户端向服务端发起连接请求

    如图,我们在请求服务器的时候,发送了这样的request header。
    下面我们就一些比较重要的字段信息进行说明:

    * Connection:Upgrade #通知服务器协议升级 Upgrade:websocket  #协议升级为websocket协议
    * Host:0.0.0.0:9501  #升级协议的服务主机:端口地址
    * Sec-WebSocket-Key:K8o1cNIxO2pR6inTIDBSgg== #传输给服务器的key
    * Sec-WebSocket-Version:13 #websocket协议版本13

    Sec-WebSocket-Key有什么用呢?客户端将这个key发送给服务器,服务器将这个key进行处理,将处理后的key返回给客户端,客户端根据这个key是否正确来判断是否建立连接。
    ②:服务端返回握手应答

    # websocket建立握手的过程
    客户端向服务端发送一个随机字符串;
    服务端获取客户端发送过来的随机字符串:在请求Sec-WebSocket-Key中获取,如:mnwFxiOlctXFN/DeMt1Amg==
    通过以下加密算法
            - base64.b64encode(hashlib.sha1(mnwFxiOlctXFN/DeMt1Amg== + magic string))
            - 返回给客户浏览器,在响应头中设置:Sec-WebSocket-Accept: 加密后的值;
    客户端在响应头中获取该加密后的字符串,然后拿着自己的那个随机字符串+magic string使用同样的方式进行加密,然后和拿到的响应加密字符串对比,如果二者一样,则握手成功,可以发送数据了。
    
    发送数据过程:对数据进行加密后发送
            - 127: 2+8字节   MASK(4字节)+数据
            - 126: 2+2字节   MASK(4字节)+数据
            - 125: 2字节     MASK(4字节)+数据

    如图,我们看到websocket协议状态码是101.

    101表示协议切换成功。

    我们查看websocket的response header。如图:

    下面解释下reponse header字段的含义

    * Connection:Upgrade #协议升级成功
    * Sec-WebSocket-Accept:GnoYH/ip/ZMh+a5rX5P/YR6e68g= #服务端处理之后的key
    * Sec-WebSocket-Version:13#websocket 协议版本号
    * Upgrade:websocket#协议升级为websocket

    至此,websocket握手成功!下面就尽情的传输数据吧!

    数据传输部分:

    数据传输需要客户端,非websocket客户端不能与websocket服务器通信,那么怎么实现websocket客户端呢?

    * Chrome/Firefox/高版本IE/Safari等浏览器内置了JS语言的WebSocket客户端
    
    * 可以使用一些扩展来实现websocket客户端。如php的swoole、workerman。
  • 相关阅读:
    [转]如何选购塑料水杯(塑料口杯、茶杯)
    【转】在sqlserver下增加MYSQL的链接服务器,实现分布式数据库开发第一步
    MySql: 查看当前登录用户,当前数据库
    python import, from xx import yy
    python class metaclass instance
    git: fatal: Not a git repository (or any of the parent directories): .git
    Python flask 基于 Flask 提供 RESTful Web 服务
    Python flask @app.route
    MySql: log 位置
    MySql: 忘记root密码
  • 原文地址:https://www.cnblogs.com/qq631243523/p/10251517.html
Copyright © 2011-2022 走看看