WebSocket协议入门:WebSocket 协议

网友投稿 949 2022-11-13

WebSocket协议入门:WebSocket 协议

WebSocket协议入门:WebSocket 协议

最早的Web应用程序使用表单和全页刷新。每当用户提交信息,浏览器将提交一个表单并读取新页面。每当有需要显示的更新信息,用户或者浏览器必须刷新整个页面,使用HTTP读取整个资源。利用JavaScript和XMLHttpRequest API,人们开发出了一组称为AJAX的技术,这项技术能够使应用程序在每次交互期间不会有不连贯的过渡。AJAX使应用程序只读取感兴趣的资源数据,并在没有导航得情况下更新页面。AJAX使用的网络协议仍然是HTTP;尽管名为XMLHttpRequest,数据也只是有时使用XML格式,而不是始终使用该格式。 本质上,HTTP用其内置的文本支持(从而支持互相连接的NTML页面)、URL和HTTPS使Web成为可能。然而,在某种程度上,HTTP的流行也造成了互联网的退化。因为HTTP不需要可寻址的客户端,Web世界的寻址变成不对称的。浏览器能够通过URL寻找服务器资源,但是服务端应用程序却无法主动地向客户端发送资源。客户端只能发起请求,而服务器只能响应未决的请求。在这个非对称的世界中,要求全双工通信的协议无法正常工作。解决这一局限的方法之一是由客户端发出HTTP请求,以放服务器有需要共享的更新。使用HTTP请求颠倒通知流程的这一过程用一个伞形术语Comet来表示。Comet本质上是一组利用轮询、长轮询和流化开发HTTP潜力的技术。这些技术实际上模拟了TCP的一些功能,以便处理上述的服务器-客户端用例。因为同步的HTTP和这些异步应用程序之间不匹配,Comet复杂、不标准且低效。

WebSocket协议

WebSocket为Web应用程序保留了HTTP的特性(URL、HTTP安全性、更简单的基于数据模型的消息和内置的文本支持),同时提供了其他网络架构和通信模式。和TCP一样,WebSocket是异步的,可以用作高级协议的传输层。WebSocket是消息协议、聊天、服务器通知、管道和多路复用协议、自定义协议、紧凑二进制协议和用于与互联网服务器互操作的其他标准协议的很好的基础。

WebSocket为Web应用程序提供了TCP风格的网络能力。寻址仍然是单向的,服务器可以异步发送客户端数据,但是只在WebSocket连接打开时才能做到。在客户端和服务器之间WebSocket连接始终打开。WebSocket服务器也可以作为WebSocket客户端。但是,利用WebSocket,Web客户端不能接受不是由它们建立的连接。

TCP只能传送字节流,所以消息边界只能由更高层的协议来表现。使用TCP的套接字编程新手常犯的一个错误是,假定每次调用send()都会得到一次成功的receive。在简单的测试中,这个假定可能恰好没错。当负载和延迟变化时,TCP套接字上发送的字节可能会有不可预测的碎片。TCP数据可能根据操作系统的喜好分布到多个IP封包或者合并为较少的封包。对于TCP来说,唯一可以保证的是,到达接收端的单个字节将会按顺序到达。和TCP不同,WebSocket传输一序列单独的消息,在WebSocket中,和HTTP一样,多字节的消息作为整体、按照顺序到达。因为WebSocket协议内置了消息边界,所以它能够发送和接收单独的消息并避免常见的碎片错误。

为互联网设计的TCP/IP协议模型由4层组成:链路层、网络层、传输层和应用层。IP处于网络层,而TCP处于IP之上的传输层。WebSocket的层次在TCP之上,因为可以在WebSocket上构建应用级协议,所以它也被看作是传输层协议。

WebSocket初始握手

每个WebSocket连接都始于一个HTTP请求。该请求和其他请求很相似,但是包含一个特殊的首标-Upgrade。Upgrade首标表示客户端将把连接升级到不同的协议。在这种情况下,这个不同的协议就是WebSocket。在这种情况下,这个不同的协议就是WebSocket。

上图展示了从客户端发往服务器升级为WebSocket的HTTP请求,也称作WebSocket初始握手(opening handshake)。有些首标是必需的,必需存在并且要精确才能保证WebSocket连接成功。这一握手中的其他首标是可选的,但因为握手是一次HTTP请求和响应,所以也是允许的。在成功升级后,连接的语法切换为用于表示WebSocket消息的数据帧格式。除非服务器响应101代码、Upgrade首标和Sec-WebSocket-Accept首标,否则WebSocket连接不能成功。Sec-WebSocket-Accept响应首标的值从Sec-WebSocket-Key请求首标继承而来,包含一个特殊的响应键值,必需与客户端的预期精确匹配。

计算响应键值

为了成功地完成握手,WebSocket服务器必须响应一个计算出来的键值。这个响应说明服务器理解WebSocket协议。响应函数从客户端发送的Sec-WebSocket-Key首标中取得键值,并在Sec-WebSocket-Accept首标中返回根据客户端预期计算的键值。

// 用Node.js加密API计算键值和后缀组合的SHA1散列值var KEY_SUFFIX = "258EAFAS-E914-47DA-95CA-C5AB0DC85B11";var hashWebSocketKey = function(key) { var sha1 = crypto.createHash("sha1"); sha1.update(key + KEY_SUFFIX, "ascii"); return sha1.digest("base64");}// KEY_SUFFIX是一个协议规范中包含的固定键值后缀,每个WebSocket服务器都必须知道。

函数流程是:从客户端发送的Sec-WebSocket-Key首标中取得键值加上协议规范中包含的固定键值后缀,通过SHA1散列函数,将输出进行base64编码,并在Sec-WebSocket-Accept首标中返回根据客户端预期计算的键值。

消息格式

当WebSSocket连接打开时,客户端和服务器可以在任何时候相互发送消息。这些消息在网络上用标记消息之间边界并包括简洁的类型信息的二进制语法表示。更准确地说,这些二进制首标标记另一个单位-帧-之间的边界。帧是可以合并组成消息的部分数据,消息可以由任意数量的帧组成。(你可能在WebSocket的相关讨论中将帧和消息互相使用,这是因为很少有一个消息使用超过一个帧,而且,在协议帧的早期草案中,帧就是消息,消息在线路上的表示被称作组帧framing)。

WebSocket帧化代码负责:操作码、长度、解码文本、屏蔽、多帧消息

操作码:每条WebSocket消息都有一个指定消息载荷类型的操作码。操作码由帧头的第一个字节中最后4bit组成。4bit的操作码有16种可能取值,WebSocket协议只定义了5种操作码,剩余的操作码保留用于未来的扩展。

长度:WebSocket协议使用可变位数来编码帧长度,小的消息就能使用紧凑的编码,协议仍然可以携带中型甚至非常大的消息。对于小于126字节的消息,长度用帧头前两个字节之一表示。对于126-216字节的消息,使用两个额外的字节表示长度。对于大于216字节的消息,长度为8字节。该长度编码保存于帧头第二个字节的最后7位。该字段中126和127两个值被当作特殊的信号,表示需要后面的字节才能完成长度编码。

解码文本:WebSocket文本消息用8位UCS转换格式(UTF-8)编码。UTF-8是用于Unicode的变长编码,向后兼容7位的ASCII,也是WebSocket文本消息允许的唯一编码。

case opcodes.TEXT: payload = buffer.toString("utf8"); //UTF-8是buffer.toString()的默认编码,这里指定格式是为了清晰

屏蔽:从浏览器向服务器发送的WebSocket帧内容进行了“屏蔽”,以混淆其内容。屏蔽的目的不是阻止窃听,而是为了不常见的安全原因,以及改进和现有HTTP代理的兼容性。帧头第二个字节的第一位表示该帧是否进行了屏蔽:WebSocket协议要求客户端屏蔽发送的所有帧。如果有屏蔽,所有的掩码将占据帧头扩展长度部分后的4个字节。WebSocket服务器接收的每个载荷在处理之前首先被解除屏蔽(用4个字节的掩码解除WebSocket帧载荷部分的屏蔽)。解除屏蔽之后,服务器得到原始消息内容:二进制消息可以直接交付;文本消息将进行UTF-8解码,并通过服务器API输出字符串。

var unmask = function(mask_bytes, buffer) { var payload = new Buffer(buffer.lenght); for(var i = 0; i < buffer.length; i++){ payload[i] = mask_bytes[i%4] ^ buffer[i]; } return payload;}

多帧消息:帧格式中的fin位考虑了多帧消息或者部分可用消息的流化,这些消息可能不连续或者不完整。要发送一条不完整的消息,你可以发送一个fin位设置为0的帧。最后一个帧的fin位设置为1,表示消息以这一帧的载荷作为结束。

WebSocket关闭握手

当WebSocket关闭时,终止连接的端点可以发送一个数字代码,以及一个表示选择关闭套接字原因的字符串。代码和原因编码为具有关闭操作码(8)的一个帧的载荷。数字代码用一个16位无符号整数表示,原因则是一个UTF-8编码的短字符串。

对其他协议的支持和扩展

WebSocket协议支持更高级的协议和协议协商。在网络层,这些协议用Sec-WebSocket-Protocol首标协商。协议名称在客户端发送初始升级请求时用首标值表示:Sec-WebSocket-Protocol: com.kaazing.echo, example.protocol.name 上述首标表示客户端可以使用任一个协议(com.kaazing.echo或example.protocol.name),服务器可以选择适用的协议。如果你在对ws://echo.websocket.org发送的升级请求中发送了这个首标,那么服务器响应中将包含如下首标:Sec-WebSocket-Protocol: com.kaazing.echo。这个响应表示,服务器选择适用com.kaazing.echo协议。这些协议在WebSocket协议之上的层次,为框架和应用程序提供更高级的语义。 连接的客户端发送一个Sec-WebSocket-Extensions首标,包含所支持的扩展名称。例如,Chrome可以发送如下首标,表明它将接受一个试验性的压缩扩展:Sec-WebSocket-Extensions: x-webkit-deflate-frame 扩展可以为帧格式添加新的操作码和数据字段。部署新扩展比新协议更困难,因为浏览器供应商必须明确地为这些扩展提供支持。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Scrapy学习笔记-Anaconda下安装
下一篇:蓝桥杯赛后总结与反思
相关文章

 发表评论

暂时没有评论,来抢沙发吧~