WebSockets简介

在2008年中期,开发人员Michael Carter和Ian Hickson特别敏锐地感受到Comet在实施任何真正强大的东西时所带来的痛苦和局限。 通过在IRC和W3C邮件列表上的合作,他们制定了一项计划,在网络上引入现代实时双向通信的新标准,因此创造了“WebSocket”这个名称。

这个想法进入了W3C HTML草案标准,不久之后,Michael Carter写了一篇文章,将Comet社区介绍给WebSockets。 2010年,谷歌Chrome 4是第一个提供对WebSockets全面支持的浏览器,其他浏览器供应商也在接下来的几年中采用了这种方式。 2011年,RFC 6455 - WebSocket协议 - 发布到IETF网站。

今天,所有主流浏览器都完全支持WebSockets,甚至包括Internet Explorer 10和11.此外,自2013年以来,iOS和Android上的浏览器都支持WebSockets,这意味着总而言之,WebSocket支持的现代环境非常健康。 大多数“物联网”或IoT也在某些版本的Android上运行,因此从2018年开始,其他类型设备上的WebSocket支持也相当普遍。

那么究竟什么是WebSockets呢?

简而言之,WebSockets是一个构建在设备TCP / IP堆栈之上的传输层。 目的是为Web应用程序开发人员提供本质上尽可能接近原始的TCP通信层,同时添加一些抽象来消除某些差异。 它们还满足了这样一个事实,即网络具有额外的安全考虑因素,必须将其考虑在内以保护消费者和服务提供者。

您可能听说WebSockets同时被称为“传输”和“协议”。前者更准确,因为虽然它们是一种协议,因为必须遵守一套严格的规则来建立通信并包含所传输的数据,但该标准并没有对如何构建实际数据有效载荷采取任何规定。事实上,规范的一部分包括客户端和服务器就一个协议达成一致的规范,传输的数据将通过该协议进行格式化和解释。该标准将这些称为“子协议”,以避免术语中含糊不清的问题。子协议的示例是JSON,XML,MQTT,WAMP等。这些不仅可以确保数据的结构方式,还可以确保通信必须开始,继续并最终终止的方式。只要双方都了解协议所包含的内容,任何事情都会发生。 WebSocket仅提供传输层,通过该传输层可以实现该消息传递过程,这就是为什么大多数常见的子协议不是基于WebSocket的通信所独有的。

关于身份验证和授权的快速说明

把WebSockets看作是一个建立在TCP / IP之上的薄层,超出基本握手和消息框架规范的任何东西都需要在每个应用程序或每个库的基础上处理。 引用RFC:

此协议未规定服务器在WebSocket握手期间可以对客户端进行身份验证的任何特定方式。 WebSocket服务器可以使用通用HTTP服务器可用的任何客户端身份验证机制,例如cookie,HTTP身份验证或TLS身份验证。

简而言之,您仍然可以使用的基于HTTP的身份验证方法,或使用MQTT或WAMP等子协议,这两种子协议都提供身份验证和授权方法。

用HTTP做连接

定义WebSocket标准时的一个早期考虑因素是确保它“与网络”很好地协同工作。 这意味着认识到Web通常使用URL而不是IP地址和端口号进行寻址,并且WebSocket连接应该能够使用Web请求相同的基于HTTP的任何其他类型进行初始握手。

这是一个简单的HTTP GET请求中发生的事情。

假设在http://www.example.com/index....。 如果不深入到HTTP协议本身,就足以知道请求必须从所谓的Request-Line开始,然后是一系列键值对标题行,每一行都告诉服务器一些关于什么的信息。 期望在随后的请求有效负载中跟随头数据,以及它可以从客户端得到的关于它能够理解的响应类型的内容。

请求中的第一个令牌是HTTP方法,它告诉服务器客户端针对引用的URL尝试的操作类型。 当客户端仅请求服务器向其提供由指定URL引用的资源的副本时,使用GET方法。

根据HTTP RFC格式化的请求标头的系统示例如下所示:


GET /index.html HTTP/1.1
Host: www.example.com

收到请求标头后,服务器然后格式化一个以状态行开头的响应标头,然后是一组键值标头对,为客户端提供来自服务器的补充信息,关于服务器的请求。 响应。 “状态行”告诉客户端HTTP状态代码(如果没有问题,通常为200),并提供解释状态代码的简短“原因”文本描述。 接下来出现键值标题对,然后是请求的实际数据(除非状态代码表明由于某种原因无法满足请求)。


HTTP/1.1 200 OK
Date: Wed, 1 Aug 2018 16:03:29 GMT
Content-Length: 291
Content-Type: text/html
(additional headers...)(response payload continues here...)

那么你可能会问,这与WebSockets有什么关系呢?

抛弃HTTP以获得更合适的东西

在发出HTTP请求并接收响应时,涉及的实际双向网络通信通过活动的TCP / IP套接字进行。浏览器中请求的Web URL通过全局DNS系统映射到IP地址,HTTP请求的默认端口为80.这意味着虽然Web URL已输入浏览器,但实际通信是通过TCP进行的/ IP,使用类似于123.11.85.9:80的IP地址和端口组合。

我们现在知道,WebSockets也建立在TCP堆栈之上,这意味着我们所需要的只是客户端和服务器共同同意保持套接字连接打开并重新利用它以进行持续通信的方式。如果他们这样做,就可以发送和接收的二进制数据。

要开始重新调整TCP套接字以进行WebSocket通信,客户端可以包含专门为此类用例发明的标准请求标头:


GET /index.html HTTP/1.1
Host: www.example.com
Connection: Upgrade
Upgrade: websocket

Connection标头告诉服务器客户端希望协商套接字使用方式的更改。 随附的值Upgrade表示当前通过TCP使用的传输协议应该更改。 现在服务器知道客户端想要通过活动TCP套接字升级当前正在使用的协议,服务器知道要查找相应的升级头,这将告诉它客户端想要使用哪个传输协议的剩余生命周期 连接。 一旦服务器将websocket视为Upgrade标头的值,它就知道WebSocket握手过程已经开始。

请注意,如果您想了解本文中介绍的更多详细信息,请参阅RFC 6455中概述了握手过程(以及其他所有内容)。

避免有趣的麻烦

除了上面描述的内容之外,WebSocket握手的第一部分涉及证明这实际上是一个正确的WebSocket升级握手,并且该过程不是通过客户端或可能通过某种中间欺骗来规避或模拟的。 位于中间的代理服务器。

启动升级到WebSocket连接时,客户端必须包含Sec-WebSocket-Key标头,该标头具有该客户端唯一的值。 这是一个例子:


Sec-WebSocket-Key: BOq0IliaPZlnbMHEBYtdjmKIL38=

如果使用现代浏览器中提供的WebSocket类,上面的内容将自动处理。 您只需在服务器端查找它并生成响应。

响应时,服务器必须将特殊GUID值258EAFA5-E914-47DA-95CA-C5AB0DC85B11附加到密钥,生成结果字符串的SHA-1哈希值,然后将其包含为Sec的base-64编码值。 它包含在响应中的WebSocket-Accept标头:


Sec-WebSocket-Accept: 5fXT1W3UfPusBQv/h6c4hnwTJzk=

在Node.js WebSocket服务器中,我们可以编写一个函数来生成这个值,如下所示:


const crypto = require('crypto');function generateAcceptValue (acceptKey) {return crypto.createHash('sha1').update(acceptKey + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', 'binary').digest('base64');
}

然后我们只需要调用这个函数,传递Sec-WebSocket-Key头的值作为参数,并在发送响应时将函数返回值设置为Sec-WebSocket-Accept头的值。

要完成握手,请将适当的HTTP响应头写入客户端套接字。 一个简单的响应看起来像这样:


HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Accept: m9raz0Lr21hfqAitCxWigVwhppA=

到目前为止,我们还没有完成握手 - 还有很多事情要考虑。

子协议 - 统一语言

客户端和服务器通常需要在给定消息内以及从一个消息到下一个消息的一段时间内,就它们如何格式化,解释和组织数据本身的兼容策略达成一致。 这就是子协议(前面提到过)的用武之地。如果客户端知道它可以处理一个或多个特定的应用程序级协议(例如WAMP,MQTT等),它可以包含它理解的协议列表。 发出初始HTTP请求。 如果它这样做,则服务器需要选择其中一个协议并将其包含在响应头中,否则将使握手失败并终止连接。

子协议请求标头示例:


Sec-WebSocket-Protocol: mqtt, wamp

服务器在响应中发出的示例倒数标题:


Sec-WebSocket-Protocol: wamp

请注意,服务器必须从客户端提供的列表中精确选择一种协议。选择多个将意味着服务器无法可靠或一致地解释后续WebSocket消息中的数据。例如,如果服务器选择了json-ld和json-schema。两者都是基于JSON标准构建的数据格式,并且会有许多边缘情况,其中一个可能被解释为另一个,从而在处理数据时导致意外错误。虽然不可否认本身不是消息传递协议,但该示例仍然适用。

当客户端和服务器都实现为从一开始就使用通用消息传递协议时,可以在初始请求中省略Sec-WebSocket-Protocol标头,在这种情况下服务器可以忽略此步骤。在实现通用服务,基础结构和工具时,子协议协商是最有用的,在这些服务,基础结构和工具中,一旦建立了WebSocket连接,就无法保证客户端和服务器都能相互理解。

通用协议的标准化名称应在IANA注册中心注册,用于WebSocket子协议名称,在本文撰写时,已经注册了36个名称,包括soap,xmpp,wamp,mqtt等。尽管注册表是将子协议名称映射到其解释的规范来源,但唯一严格的要求是客户端和服务器就其相互选择的子协议实际意味着什么达成一致,无论它是否出现在IANA注册表中。

请注意,如果客户端请求使用子协议但未提供服务器可以支持的任何内容,则服务器必须发送失败响应并关闭连接。

WebSocket扩展

还有一个标题用于定义数据有效负载编码和成帧方式的扩展,但在本文时,只存在一种标准化扩展类型,它提供了一种WebSocket - 等同于消息中的gzip压缩。 扩展可能发挥作用的另一个例子是多路复用 - 使用单个套接字来交错多个并发通信流。

WebSocket扩展是一个有点高级的主题,并且超出了本文的范围。 现在,它足以知道它们是什么,以及它们如何适应图片。

客户端 - 在浏览器中使用WebSockets

WebSocket API在WHATWG HTML Living Standard中定义,实际上非常简单易用。 构造WebSocket需要一行代码:


const ws = new WebSocket('ws://example.org');

注意使用ws,你通常有http方案。 您也可以选择使用wss,通常使用https。 这些协议与WebSocket规范一起引入,旨在表示HTTP连接,其中包括升级连接以使用WebSockets的请求。

创建WebSocket对象本身并没有做很多事情。 连接是异步建立的,因此您需要在发送任何消息之前侦听握手的完成,并且还包括从服务器接收的消息的侦听器:


ws.addEventListener('open', () => {// Send a message to the WebSocket serverws.send('Hello!');
});ws.addEventListener('message', event => {// The `event` object is a typical DOM event object, and the message data sent// by the server is stored in the `data` propertyconsole.log('Received:', event.data);
});

还有错误和关闭事件。 连接终止时WebSockets不会自动恢复 - 这是您需要自己实现的,并且是存在许多客户端库的原因之一。 虽然WebSocket类简单易用,但它实际上只是一个基本的构建块。 必须单独实现对不同子协议或消息传递通道等附加功能的支持。

生成和解析WebSocket消息帧

一旦将握手响应发送到客户端,客户端和服务器就可以使用他们选择的子协议(如果有的话)开始通信。

WebSocket消息在名为“frames”的包中传递,这些包以消息头开头,并以“payload”结尾 - 此帧的消息数据。 大型消息可能会将数据分成几帧,在这种情况下,您需要跟踪到目前为止收到的内容,并在数据全部到达后将数据分组。

翻译的很乱,但愿对你有点帮助

原文地址:https://segmentfault.com/a/1190000017282755

深入探索WebSockets相关推荐

  1. JavaScript 工作原理之五-深入理解 WebSockets 和带有 SSE 机制的HTTP/2 以及正确的使用姿势(译)...

    原文请查阅这里,略有改动,本文采用知识共享署名 4.0 国际许可协议共享,BY Troland. 本系列持续更新中,Github 地址请查阅这里. 这是 JavaScript 工作原理的第五章. 现在 ...

  2. pythonrsv分割_JavaScript是如何工作: 深入探索 websocket 和HTTP/2与SSE +如何选择正确的路径!...

    文章底部分享给大家一套 react + socket 实战教程 这是专门探索 JavaScript 及其所构建的组件的系列文章的第5篇. 想优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! ...

  3. 探索 TVM 进行量化方法

    探索 TVM 进行量化方法 Relay框架 如上图所示,有两种不同的并行工作正在进行中 • 自动整数量化 - 采用 FP32 框架图,在 Relay 中自动转换为 Int8. • 接受预量化整数模型 ...

  4. 自主数据类型:在TVM中启用自定义数据类型探索

    自主数据类型:在TVM中启用自定义数据类型探索 介绍 在设计加速器时,一个重要的决定是如何在硬件中近似地表示实数.这个问题有一个长期的行业标准解决方案:IEEE 754浮点标准.1.然而,当试图通过构 ...

  5. 2021年大数据ELK(二十六):探索数据(Discovery)

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 探索数据(Discovery) 一.使用探索数据功能 二.导入更多的Apach ...

  6. Python数据挖掘:数据探索,数据清洗,异常值处理

    来源:天善智能韦玮老师 课堂笔记 作者:Dust 探索性数据分析Exploratory Data Analysis,EDA 数据探索的核心是︰ 1.数据质量分析(跟数据清洗密切联系) 2.数据特征分析 ...

  7. oracle无创建directory权限,【DIRECTORY】普通用户创建Oracle DIRECTORY数据库对象的权限需求及探索...

    可能遇到的报错信息如若在创建DIRECTORY之前普通用户sec未获得相应权限,将会收到最为常见的"ORA-01031: insufficient privileges"错误.模拟 ...

  8. sources root pycharm 怎么设置_使用python语言开发ROOT之搭建环境方法探索

    这里指的是使用python调用ROOT的模块,编写程序用来处理数据的环境搭建方法. 经过研究,一般有四种方案 环境变量法,主要依靠ROOT本身,环境变量是关键 预编译包,但是该方法没有证实成功搭建py ...

  9. 论计算机的创新性,论计算机专业教学创新探索

    1/4论计算机专业教学创新探索改革高校计算机专业实训课程教学方法的重要意义高校计算机专业实训课程是计算机专业的实践课程,在计算机专业课程体系中处于非常重要的位置,主要用于培养计算机专业学生实践应用能力 ...

  10. mysql 集群实践_MySQL Cluster集群探索与实践

    MySQL集群是一种在无共享架构(SNA,Share Nothing Architecture)系统里应用内存数据库集群的技术.这种无共享的架构可以使得系统使用低廉的硬件获取高的可扩展性. MySQL ...

最新文章

  1. 【错误记录】Flutter 构建报错 ( Because xxx requires SDK version >=2.12.0-0 <3.0.0, versio | Dart SDK 版本低 )
  2. CROC-MBTU 2012, Elimination Round (ACM-ICPC) 总结
  3. dockerfile使用(一)
  4. Centos php5.3.3 升级 5.5.26 mysql5.1.73 升级 5.6.25
  5. android mvp快速创建,学习MVPArms历程之Android Studio快速创建ArmsComponent组件化项目
  6. 【计算机网络】信源编码——香农三大定理
  7. 北京航空航天大学计算机学院保研率,北京航空航天大学计算机学院(专业学位)计算机技术保研夏令营...
  8. V2X车联网-学习整理笔记
  9. Android Bluetooth蓝牙scan过程
  10. Spark之任务流程和角色
  11. CAN总线车联网透传云网关简介
  12. 2019石油大学西方艺术赏析第二阶段在线作业(答案)
  13. 面向对象的三大基本特性,五大基本原则。
  14. 残差网络(Residual Network)
  15. 社交电商和传统电商的区别。
  16. Android 疑难杂症系列
  17. 中创易票通打印票据支票 v2.3 bt
  18. ModbusTCP协议报文解析
  19. python大乐透代码_scrapy框架爬取大乐透数据
  20. MATLAB红苹果提取(颜色分割)

热门文章

  1. Linux应用层24点小游戏,C++ Builder构建算二十四点小游戏
  2. java cryptojs_使用cryptojs的Java到JS和JS到Java的加密
  3. VS2012更改/重置默认开发环境
  4. 2018.07.27
  5. LED灯具检验标准与方法
  6. Windows下QT5.9构建的debug或release文件打包后不能使用
  7. python零基础教学plc_编程零基础应当如何开始学习 Python?
  8. 【原创】Magisk Root隐藏模块 Shamiko安装
  9. fclk if总线_技嘉B550手把手超频指南,光威血影为例
  10. Html转Word解决转存图片时候的跨域问题、默认打开视图问题