认识websocket

7 篇文章 0 订阅
2 篇文章 0 订阅

正式开讲之前我们先来看一下一般的http请求应答是什么样子的
这里写图片描述
这里写图片描述
请同学们注意connection的状态 connection:keep-alive以及Request URL的格式,与下图作比较

再来看下websocket的请求应答又是什么样子的
这里写图片描述
在Response Headers和Request Headers右边点击view source会看到以下的展示:
这里写图片描述
从websocket连接中我们可以看到connection:Upgrade,而Upgrade:websocket

先上图只是为了更直观的了解HTTP与websocket区别与联系,接下来带着图开讲

1. Websocket协议的简单介绍

WebSocket的目的就是解决网络传输中的双向通信的问题

WebSocket协议实现在受控环境中运行不受信任代码的一个客户端到一个从该代码已经选择加入通信的远程主机之间的全双工通信。用于这个的安全模型是通常由web浏览器使用的基于来源的安全模型。该协议包括一个打开阶段握手、接着是基本消息帧、TCP之上的分层(layered over TCP)。该技术的目标是为需要与服务器全双工通信且不需要依赖打开多个HTTP连接(例如,使用XMLHttpRequest或和长轮询)的基于浏览器应用的提供一种机制。

1.1.背景

不久前,创建需要在客户端和服务器之间双向通信(例如,即时消息和游戏应用)的web应用, 需要一个滥用的HTTP(多次建立或者使用http连接)来轮询服务器进行更新但以不同的HTTP调用发生上行通知。

由此带来的问题:

  • 服务器被迫为每个客户端使用一些不同的底层TCP连接: 一个用于发送信息到客户端和一个新的用于每个传入消息。

  • 线路层协议有较高的开销,因为每个客户端-服务器消息都有一个HTTP头信息。

  • 客户端脚本被迫维护一个传出的连接到传入的连接的映射来跟踪回复。

一个简单的办法是使用单个TCP连接双向传输。这是为什么提供WebSocket 协议。与WebSocket API结合[WSAPI],它提供了一个HTTP轮询的替代来进行从web 页面到远程服务器的双向通信。 同样的技术可以用于各种各样的web应用:

游戏、股票行情、同时编辑的多用户应用、服务器端服务以实时暴露的用户接口、等等。

WebSocket协议被设计来取代现有的使用HTTP作为传输层的双向通信技术,并受益于现有的基础设施(代理、过滤、身份验证)。这样的技术被实现来在效率和可靠性之间权衡,因为HTTP最初目的不是用于双向通信(参见[RFC6202]的进一步讨论)。WebSocket协议试图在现有的HTTP基础设施上下文中解决现有的双向HTTP技术目标;同样,它被设计工作在HTTP端口80和443,也支持HTTP代理和中间件,即使这具体到当前环境意味着一些复杂性。但是,这种设计不限制WebSocket到HTTP,且未来的实现可以在一个专用的端口上使用一个更简单的握手,且没有再创造整个协议。最后一点是很重要的,因为交互消息的传输模式不精确地匹配标准HTTP传输并可能在相同组件上包含不常见的负载。

1.2.协议概述

websocket协议有两部分:握手和数据传输。
来自客户端的握手看起来像如下形式:

GET ws://192.168.100.2:12345/ HTTP/1.1
Host: 192.168.100.2:12345
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: file://
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8
Sec-WebSocket-Key: inmAp8QYV+1UVOc8NLZv+g==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

来自服务器的握手看起来像如下形式:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: opNsUiGCrFfreIzx7UmRZC/+sDc=
WebSocket-Origin: file://
WebSocket-Location: ws://192.168.100.2:12345/

一旦客户端和服务器都发送了它们的握手,且如果握手成功,接着开始数据传输部分。这是一个每一端都可以的双向通信信道,彼此独立,随意发生数据。

一个成功握手之后,客户端和服务器来回地传输数据,在本规范中提到的概念单位为“消息”。在线路上,一个消息是由一个或多个帧的组成。WebSocket的消息并不一定对应于一个特定的网络层帧,可以作为一个可以被一个中间件合并或分解的片段消息。

一个帧有一个相应的类型。属于相同消息的每一帧包含相同类型的数据。从广义上讲,有文本数据类型(它被解释为UTF-8[RFC3629]文本)、二进制数据类型(它的解释是留给应用)、和控制帧类型(它是不准备包含用于应用的数据,而是协议级的信号,例如应关闭连接的信号)。这个版本的协议定义了六个帧类型并保留10以备将来使用。

1.3.打开阶段握手

打开阶段握手目的是兼容基于HTTP的服务器软件和中间件,以便单个端口可以用于与服务器交流的HTTP客户端和与服务器交流的WebSocket客户端。

依照[RFC2616],握手中的头字段可能由客户端按照任意顺序发送,因此在接收的不同头字段中的顺序是不重要的。

“Request-URI”的GET方法[RFC2616]用于识别WebSocket连接的端点,即允许从一个IP地址服务的多个域名,也允许由单台服务器服务的多个WebSocket端点。 客户端按照[RFC2616]在它的握手的|Host|头字段中包含主机名,以便客户端和服务器都都能验证他们同意哪一个正在使用的主机。

在WebSocket协议中另外的头字段可以用于选择选项。典型的选项在这个版本中可用的是子协议选择器(|Sec-WebSocket-Protocol|)、客户端支持的扩展列表(|Sec-WebSocket-Extensions|)、|Origin|头字段等。|Sec-WebSocket-Protocol|请求头字段可以用来表示客户端接受的子协议(WebSocket协议上的应用级协议层)。服务器选择一个可接受的协议或不,并在它的握手中回应该值表示它已经选择了那个协议。

    Sec-WebSocket-Protocol: chat

|Origin|头字段[RFC6454]是用于保护防止未授权的被浏览器中的使用WebSocket API的脚本跨域使用WebSocket服务器。服务器收到WebSocket连接请求生成的脚本来源。如果服务器不想接受来自此来源的连接,它可以选择通过发送一个适当的HTTP错误码拒绝该连接。这个头字段由浏览器客户端发送,对于非浏览器客户端,如果它在这些客户端上下文中有意义,这个头字段可以被发送。

最后,服务器要证明收到客户端WebSocket握手的客户端,以便服务器不接受不是WebSocket连接的连接。这可以防止一个通过使用XMLHttpRequest [XMLHttpRequest]或一个表单提交发送它精心制作的包欺骗WebSocket服务器的攻击者。

为了证明收到的握手,服务器必须携带两条信息并组合他们形成一个响应。

第一条信息源自客户端握手中的| Sec-WebSocket-Key |头信息: Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

对于这个头字段,服务器必须携带其值(出现在头字段上,如,减去开头和结尾空格的base64-编码[RFC4648]的版本)并将这个与字符串形式的全局唯一标识符(GUID,[RFC4122])“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”连接起来,其不太可能被不理解WebSocket协议的网络端点使用。SHA-1散列(160位)[FIPS.180-3]、base-64编码(参见[RFC4648]第4章)、用于这个的一系列相关事物接着在服务器握手过程中返回。

1.4.关闭阶段握手

两个节点中的任一个都能发送一个控制帧与包含一个指定控制序列的数据来开始关闭阶段握手(详见5.5.1节)。在收到这样一个帧时,另一个节点在响应中发送一个Close帧,如果还没有发送一个。在收到那个控制帧时,第一个节点接着关闭连接,安全地知道没有更多的数据到来。

发送一个控制帧之后,表示连接将被关闭,一个节点不会发送任何更多的数据;在接收到一个控制帧之后,表示连接将被关闭,一个节点会丢弃收到的任何更多的数据。

对于两个节点同时地初始化这个握手是安全的。

关闭阶段握手目的是完成TCP关闭握手(FIN/ACK),基于TCP关闭阶段握手不总是可靠的端到端,尤其在存在拦截代理和中间件。 通过发送一个Close帧并等待响应中的Close帧,某些情况下可避免数据不必要的丢失。例如,在某些平台上,如果一个socket关闭了,且接收队列中有数据,一个RST包被发送了,这样会导致接受RST的一方的recv()失败,即使有数据等待读取。

1.5.设计理念

WebSocket协议应该以最小帧的原则设计(唯一存在的框架是使协议基于帧而不是基于流且支持区分Unicode文本和二进制帧)。期望通过应用层将元数据分层在WebSocket之上,同样地,通过应用层将元数据分层在TCP之上(例如,HTTP)。

从概念上讲,WebSocket只是TCP之上的一层,执行以下操作:

  • 为浏览器添加一个web 基于来源的安全模型

  • 添加一个寻址和协议命名机制来支持在一个IP地址的一个端口的多个主机名的多个服务

  • 在TCP之上分一个帧机制层以回到TCP基于的IP包机制,但没有长度限制

  • 包括一个额外的带内(in-band)关闭阶段握手,其被设计来工作在现存的代理和其他中间件。

除此之外,WebSocket没有添加任何东西。基本上,它的目的是尽可能接近仅暴露原始TCP到脚本,尽可能考虑到Web的约束。它也被设计为它的服务器能与HTTP服务器共享一个端口的这样一种方式,通过持有它的握手是一个有效的HTTP Upgrade请求。一个可以在概念上使用其他协议来建立客户端-服务器消息,但WebSocket的意图是提供一个相对简单的协议,可以与现有HTTP和部署的HTTP基础设施(例如代理)同时存在,并尽可能接近TCP,且对于使用考虑到安全考虑的这样的基础设施同样是安全的,有针对性的补充以简化使用并保持简单的事情简单(如增加的消息语义)。

1.6.安全模型

WebSocket协议使用浏览器使用的来源模型限制web页面可以与WebSocket服务器通信,当WebSocket协议是从一个web页面使用。当然,当WebSocket协议被一个独立的客户端直接使用时(也就是,不是从浏览器中的一个web页面),来源模型不再有用,因为客户端可以提供任意随意的来源字符串。

该协议的目的是无法与现有的协议如SMTP[RFC5321]和HTTP建立一个连接,同时允许HTTP服务器来选择支持该协议如果想要。这是通过具有严格的和详尽的握手和通过限制在握手完成之前能被插入到连接的数据(因此限制多少服务器可以被应用)实现的。

当数据是来自其他协议时,同样的目的是无法建立连接的,尤其发送到一个WebSocket服务器的HTTP,例如,如果一个HTML“表单”提交到WebScoket服务器可能会发生。这主要通过要求服务器验证它读取的握手来实现,它只能做 如果握手包含适当的部分,只能通过一个WebScoket客户端发送。尤其是,在写本规范的时侯,|Sec-|开头的字段不能由web浏览器的攻击者设置,仅能使用HTML和JavaScript API,例如XMLHttpRequest [XMLHttpRequest]。

2. WebSocket URI

WebSocket规范定义了两个URI方案,使用定义在RFC5234[RFC5234]中的ABNF句法、和术语和由URI规范RFC 3986 [RFC3986]定义的ABNF制品。

  ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
  wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]

  host = <host, defined in [RFC3986], Section 3.2.2>
  port = <port, defined in [RFC3986], Section 3.2.3>
  path = <path-abempty, defined in [RFC3986], Section 3.3>
  query = <query, defined in [RFC3986], Section 3.4>

端口组件是可选的;用于“WS”的默认端点是80,而用于“WSS”默认端口是443(有点类似http和https的感觉)。

如果方案组件不区分大写匹配“wss”,URI被称为“安全的”(它是说,“设置了安全标记”)。

“resource-name”(在4.1节也称为/resource name/)可以通过连接以下来构造:

  • “/” 如果路径组件是空

  • 路径组件

  • “?” 如果查询组件是非空

  • 查询组件

3. 数据帧

在WebSocket协议中,数据使用帧序列来传输。为避免混淆网络中间件(例如拦截代理)和出于安全原因,客户端必须掩码(mask)它发送到服务器的所有帧。(注意不管WebSocket协议是否运行在TLS之上,掩码都要做。) 当收到一个没有掩码的帧时,服务器必须关闭连接。在这种情况下,服务器可能发送一个状态码1002(协议错误)的Close帧。服务器必须不掩码发送到客户端的所有帧。如果客户端检测到掩码的帧,它必须关闭连接。在这种情况下,它可能使用的状态码1002(协议错误)。

基本帧协议定义了带有操作码(opcode)的帧类型、负载长度、和用于“扩展数据”与“应用数据”及它们一起定义的“负载数据”的指定位置。某些字节和操作吗保留用于未来协议的扩展。

一个数据帧可以被客户端或者服务器在打开阶段握手完成之后和端点发送Close帧之前的任何时候传输。

3.1 基本帧协议

下图给出了帧的高层次概述
这里写图片描述

每一位代表的含义:

FIN 1bit 指示这个是消息的最后片段。第一个片段可能也是最后的片段
RSV 1-3 1bit 必须是0,除非一个扩展协商为非零值定义含义。如果收到一个非零值且没有协商的扩展定义这个非零值的含义,接收端点必须失败WebSokcket连接。
Opcode 4bit 定义了“负载数据”的解释。如果收到一个未知的操作码,接收端点必须失败WebSocket连接。
Mask 1bit 掩码,是否加密数据,默认必须置为1
Payload 7bit “负载数据”的长度
Masking-key 1 or 4 bit 掩码
Payload data (x + y) bytes 数据
Extension data x bytes 扩展数据
Application data y bytes 程序数据

4. 发送和接收数据

4.1.发送数据

为了发送一个WebSocket消息,其中包括WebSocket连接之上的/data/,端点必须执行以下步骤:

  • 1.端点必须确保WebSocket连接处于OPEN状态(比较 4.1节和4.2.2节)。如果在任何时刻WebSocket连接的状态改变了,端点必须终止以下步骤。

  • 2.端点必须封装/data/到定义在5.2节的一个WebSocket帧。如果要发送的数据太大或如果在端点想要开始发生数据时数据作为一个整体不可用,端点可以按照5.2节的定义交替地封装数据到一系列的帧中。

  • 3.第一个包含数据的帧的操作码(帧-opcode)必须按照5.2节的定义被设置为适当的值用于接收者解释数据是文本还是二进制数据。。

  • 4.包含数据的最后帧的FIN位(帧-fin)必须按照5.2节的定义设置位1。

  • 5.如果数据正由客户端发送,帧必须按照5.3节的定义被掩码。

  • 6.如果任何扩展(第9章)已经协商用于WebSocket连接,额外的考虑可以按照这些扩展定义来应用。

  • 7.已成形的帧必须在底层网络连接之上传输。

4.2.接收数据

为了接收WebSocket数据,端点监听底层网络连接。传入数据必须按照定义解析为WebSocket帧。如果接收到一个控制帧,帧必须定义的来处理。当接收到一个数据帧时,端点必须注意由操作码(帧-opcode)定义的数据的/type/。这个帧的“应用数据”被定义为消息的/data/。如果帧由一个未分片的消息组成,这是说已经接收到一个WebSocket消息,其类型为/type/且数据为/data/。如果帧是一个分片消息的一部分,随后数据帧的“应用数据”连接在一起形成/data/。当接收到由FIN位(帧-fin)指示的最后的片段时,这是说已经接收到一个WebSocket消息,其数据为/data/(由连续片段的“应用数据”组成)且类型为/type/(分配消息的第一个帧指出)。随后的数据帧必须被解释为属于一个新的WebSocket消息。

常规理论就到这,补充内容如下

一般情况下双向通信(客户端要向服务器传送数据,同时服务器也需要实时的向客户端传送信息,一个聊天系统就是典型的双向通信)时有以下几种解决方案:

  • 轮询(polling),轮询就会造成对网络和通信双方的资源的浪费,且非实时。

  • 长轮询,客户端发送一个超时时间很长的Request,服务器hold住这个连接,在有新数据到达时返回Response,相比#1,占用的网络带宽少了,其他类似。

  • 长连接,其实有些人对长连接的概念是模糊不清的,我这里讲的其实是HTTP的长连接(1)。如果你使用Socket来建立TCP的长连接(2),那么,这个长连接(2)跟我们这里要讨论的WebSocket是一样的,实际上TCP长连接就是WebSocket的基础,但是如果是HTTP的长连接,本质上还是Request/Response消息对,仍然会造成资源的浪费、实时性不强等问题。
    来张图直观了解下以上提及
    这里写图片描述

左边图示可以说是轮训,右边的话就是长连接,也可以说是websocket的运作方式,长轮询就是说左边图中的每一个轮询保持了很长时间的连接而已。

websocket与HTTP比较

同样作为应用层的协议,WebSocket和HTTP有很多相似的地方,但也有各自的特点,以下本人总结一些:

相同点

都是基于TCP的应用层协议。
都使用Request/Response模型进行连接的建立。
在连接的建立过程中对错误的处理方式相同,在这个阶段WS可能返回和HTTP相同的返回码。
都可以在网络中传输数据。

不同点

WS使用HTTP来建立连接,但是定义了一系列新的header域,这些域在HTTP中并不会使用。
WS的连接不能通过中间人来转发,它必须是一个直接连接。
WS连接建立之后,通信双方都可以在任何时刻向另一方发送数据。
WS连接建立之后,数据的传输使用帧来传递,不再需要Request消息。
WS的数据帧有序。

讲到websocket,是因为本人正在做一个在线聊天的小程序,所以就了解了一下,在此展示一张应用登录页,具体的应用实现及效果展示将在下篇博客以及本人GitHub中细出,有兴趣的同学可以一起来玩。

这里写图片描述

本文大部分内容摘自https://www.w3cschool.cn/websocket_protocol/

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值