关于websocket:WebSocket从入门到精通半小时就够

11次阅读

共计 11511 个字符,预计需要花费 29 分钟才能阅读完成。

本文原题“WebSocket:5 分钟从入门到精通”,作者“程序猿小卡_casper”,原文链接见文末参考资料局部。本次收录时有改变。

1、引言

自从 HTML5 里的 WebSocket 呈现后,彻底改变了以往 Web 端即时通讯技术的根底通道这个“痛点”(在此之前,开发者们不得不弄出了诸如:短轮询、长轮询、Comet、SSE 等技术,堪称苦之久矣 …),现在再也不必纠结到底该用“轮询”还是“Comet”技术来保证数据的实时性了,幸福来的就是如此忽然 ^-^。

WebSocket 现在不仅在 Web 利用里应用宽泛,也缓缓被开发者们利用到各种那些本来应用 TCP、UDP 这类协定的富客户端(比方挪动端中)。

有鉴于此,对于即时通讯方向的开发者来说,全面深刻的理解 WebSocket 是十分有必要的,面视时也少不了会考查这方面的常识。

所以,即时通讯网在建站至今的几年工夫里,继续整顿了一大批跟 Web 端即时通讯无关的技术文章(这基中尤其 WebSocket 方面的文章最多)。本文也是一篇对于 WebSocket 从入门到精通的文章,内容由浅入深,比拟适宜想要在短时间内较深刻的理解 WebSocket 协定的开发者学习。

(本文同步公布于:http://www.52im.net/thread-3134-1-1.html)

2、相干文章

《WebSocket 详解(一):初步意识 WebSocket 技术》
《WebSocket 详解(二):技术原理、代码演示和利用案例》
《WebSocket 详解(三):深刻 WebSocket 通信协议细节》
《WebSocket 详解(四):刨根问底 HTTP 与 WebSocket 的关系 (上篇)》
《WebSocket 详解(五):刨根问底 HTTP 与 WebSocket 的关系 (下篇)》
《WebSocket 详解(六):刨根问底 WebSocket 与 Socket 的关系》

3、注释概览

WebSocket 的呈现,使得浏览器具备了实时双向通信的能力。

本文将由浅入深,介绍 WebSocket 如何建设连贯、替换数据的细节,以及数据帧的格局。此外,还简要介绍了针对 WebSocket 的平安攻打,以及协定是如何抵挡相似攻打的。

4、什么是 WebSocket

4.1 根本介绍

HTML5 开始提供的一种浏览器与服务器进行全双工通信的网络技术,属于应用层协定。它基于 TCP 传输协定,并复用 HTTP 的握手通道。

对大部分 web 开发者来说,下面这段形容有点干燥,其实只有记住几点:

  • 1)WebSocket 能够在浏览器里应用;
  • 2)反对双向通信;
  • 3)应用很简略。

4.2 有哪些长处

说到长处,这里的比照参照物是 HTTP 协定,概括地说就是:反对双向通信,更灵便,更高效,可扩展性更好。

  • 1)反对双向通信,实时性更强;
  • 2)更好的二进制反对;
  • 3)较少的管制开销。连贯创立后,ws 客户端、服务端进行数据交换时,协定管制的数据包头部较小。在不蕴含头部的状况下,服务端到客户端的包头只有 2~10 字节(取决于数据包长度),客户端到服务端的的话,须要加上额定的 4 字节的掩码。而 HTTP 协定每次通信都须要携带残缺的头部;
  • 4)反对扩大。ws 协定定义了扩大,用户能够扩大协定,或者实现自定义的子协定。(比方反对自定义压缩算法等)

对于前面两点,没有钻研过 WebSocket 协定标准的同学可能了解起来不够直观,但不影响对 WebSocket 的学习和应用。

4.3 须要学习哪些货色

对网络应用层协定的学习来说,最重要的往往就是连贯建设过程、数据交换过程。当然,数据的格局是逃不掉的,因为它间接决定了协定自身的能力。好的数据格式能让协定更高效、扩展性更好。

下文次要围绕上面几点开展:

  • 1)如何建设连贯;
  • 2)如何替换数据;
  • 3)数据帧格局;
  • 4)如何维持连贯。

5、入门演示代码

在正式介绍协定细节前,先来看一个简略的例子,有个直观感触。例子包含了 WebSocket 服务端、WebSocket 客户端(网页端)。残缺代码能够在这里 找到。

这里服务端用了 ws 这个库。相比大家相熟的 socket.io,ws 实现更轻量,更适宜学习的目标。

5.1 服务端

代码如下,监听 8080 端口。当有新的连贯申请达到时,打印日志,同时向客户端发送音讯。当收到到来自客户端的音讯时,同样打印日志。

var app = require(‘express’)();
var server = require(‘http’).Server(app);
var WebSocket = require(‘ws’);
var wss = newWebSocket.Server({port: 8080});
wss.on(‘connection’, function connection(ws) {
    console.log(‘server: receive connection.’);
    ws.on(‘message’, functionincoming(message) {
        console.log(‘server: received: %s’, message);
    });
    ws.send(‘world’);
});
app.get(‘/’, function(req, res) {
  res.sendfile(__dirname + ‘/index.html’);
});
app.listen(3000);

5.2 客户端

代码如下,向 8080 端口发动 WebSocket 连贯。连贯建设后,打印日志,同时向服务端发送音讯。接管到来自服务端的音讯后,同样打印日志。

<script>
  var ws = new WebSocket(‘ws://localhost:8080’);
  ws.onopen = function() {
    console.log(‘ws onopen’);
    ws.send(‘from client: hello’);
  };
  ws.onmessage = function(e) {
    console.log(‘ws onmessage’);
    console.log(‘from server: ‘+ e.data);
  };
</script>

5.3 运行后果

可别离查看服务端、客户端的日志,这里不开展。

服务端输入:

server: receive connection.
server: received hello

客户端输入:

client: ws connection is open
client: received world

6、如何建设连贯

后面提到,WebSocket 复用了 HTTP 的握手通道。具体指的是,客户端通过 HTTP 申请与 WebSocket 服务端协商降级协定。协定降级实现后,后续的数据交换则遵循 WebSocket 的协定。

6.1 客户端:申请协定降级

首先,客户端发动协定降级申请。能够看到,采纳的是规范的 HTTP 报文格式,且只反对 GET 办法。

GET / HTTP/1.1
Host: localhost:8080
Origin:http: //127.0.0.1:3000
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: w4v7O6xFTi36lq3RNcgctw==

重点申请首部意义如下:

  • 1)Connection: Upgrade:示意要降级协定;
  • 2)Upgrade: websocket:示意要降级到 websocket 协定;
  • 3)Sec-WebSocket-Version: 13:示意 websocket 的版本。如果服务端不反对该版本,须要返回一个 Sec-WebSocket-Versionheader,外面蕴含服务端反对的版本号;
  • 4)Sec-WebSocket-Key:与前面服务端响应首部的 Sec-WebSocket-Accept 是配套的,提供根本的防护,比方歹意的连贯,或者无心的连贯。

留神:下面申请省略了局部非重点申请首部。因为是规范的 HTTP 申请,相似 Host、Origin、Cookie 等申请首部会照常发送。在握手阶段,能够通过相干申请首部进行 平安限度、权限校验等。

6.2 服务端:响应协定降级

服务端返回内容如下,状态代码 101 示意协定切换。到此实现协定降级,后续的数据交互都依照新的协定来。

HTTP/1.1 101 Switching Protocols
Connection:Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: Oy4NRAQ13jhfONC7bP8dTKb4PTU=

备注: 每个 header 都以 rn 结尾,并且最初一行加上一个额定的空行 rn。此外,服务端回应的 HTTP 状态码只能在握手阶段应用。过了握手阶段后,就只能采纳特定的错误码。

6.3 Sec-WebSocket-Accept 的计算

Sec-WebSocket-Accept 依据客户端申请首部的 Sec-WebSocket-Key 计算出来。

计算公式为:

  • 1)将 Sec-WebSocket-Key 跟 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 拼接;
  • 2)通过 SHA1 计算出摘要,并转成 base64 字符串。

伪代码如下:

toBase64(sha1( Sec-WebSocket-Key + 258EAFA5-E914-47DA-95CA-C5AB0DC85B11) )

验证下后面的返回后果:

const crypto = require(‘crypto’);
const magic = ‘258EAFA5-E914-47DA-95CA-C5AB0DC85B11’;
const secWebSocketKey = ‘w4v7O6xFTi36lq3RNcgctw==’;
let secWebSocketAccept = crypto.createHash(‘sha1’)
    .update(secWebSocketKey + magic)
    .digest(‘base64’);
console.log(secWebSocketAccept);
// Oy4NRAQ13jhfONC7bP8dTKb4PTU=

7、数据帧格局

7.1 概述

客户端、服务端数据的替换,离不开数据帧格局的定义。因而,在理论解说数据交换之前,咱们先来看下 WebSocket 的数据帧格局。

WebSocket 客户端、服务端通信的最小单位是帧(frame),由 1 个或多个帧组成一条残缺的音讯(message)。

  • 1)发送端:将音讯切割成多个帧,并发送给服务端;
  • 2)接收端:接管音讯帧,并将关联的帧从新组装成残缺的音讯。

本节的重点,就是解说数据帧的格局。具体定义可参考 RFC6455 5.2 节。

7.2 数据帧格局概览

上面给出了 WebSocket 数据帧的对立格局。相熟 TCP/IP 协定的同学对这样的图应该不生疏。

  • 1)从左到右,单位是比特。比方 FIN、RSV1 各占据 1 比特,opcode 占据 4 比特;
  • 2)内容包含了标识、操作代码、掩码、数据、数据长度等。(下一大节会开展)

7.3 数据帧格局详解

针对后面的格局概览图,这里一一字段进行解说,如有不分明之处,可参考协定标准,或留言交换。

_1)FIN:_1 个比特。

如果是 1,示意这是音讯(message)的最初一个分片(fragment),如果是 0,示意不是是音讯(message)的最初一个分片(fragment)。

2)RSV1, RSV2, RSV3: 各占 1 个比特。

个别状况下全为 0。当客户端、服务端协商采纳 WebSocket 扩大时,这三个标记位能够非 0,且值的含意由扩大进行定义。如果呈现非零的值,且并没有采纳 WebSocket 扩大,连贯出错。

3)Opcode: 4 个比特。

操作代码,Opcode 的值决定了应该如何解析后续的数据载荷(data payload)。如果操作代码是不意识的,那么接收端应该断开连接(fail the connection)。

可选的操作代码如下:

%x0:示意一个连续帧。当 Opcode 为 0 时,示意本次数据传输采纳了数据分片,以后收到的数据帧为其中一个数据分片。
%x1:示意这是一个文本帧(frame)
%x2:示意这是一个二进制帧(frame)
%x3-7:保留的操作代码,用于后续定义的非管制帧。
%x8:示意连贯断开。
%x9:示意这是一个 ping 操作。
%xA:示意这是一个 pong 操作。
%xB-F:保留的操作代码,用于后续定义的管制帧。

4)Mask: 1 个比特。

示意是否要对数据载荷进行掩码操作。从客户端向服务端发送数据时,须要对数据进行掩码操作;从服务端向客户端发送数据时,不须要对数据进行掩码操作。

如果服务端接管到的数据没有进行过掩码操作,服务端须要断开连接。

如果 Mask 是 1,那么在 Masking-key 中会定义一个掩码键(masking key),并用这个掩码键来对数据载荷进行反掩码。所有客户端发送到服务端的数据帧,Mask 都是 1。

掩码的算法、用处在下一大节解说。

5)Payload length: 数据载荷的长度,单位是字节。为 7 位,或 7 +16 位,或 1 +64 位。

假如数 Payload length === x,如果:

x 为 0~126:数据的长度为 x 字节。
x 为 126:后续 2 个字节代表一个 16 位的无符号整数,该无符号整数的值为数据的长度。
x 为 127:后续 8 个字节代表一个 64 位的无符号整数(最高位为 0),该无符号整数的值为数据的长度。

此外,如果 payload length 占用了多个字节的话,payload length 的二进制表白采纳网络序(big endian,重要的位在前)。

6)Masking-key: 0 或 4 字节(32 位)

所有从客户端传送到服务端的数据帧,数据载荷都进行了掩码操作,Mask 为 1,且携带了 4 字节的 Masking-key。如果 Mask 为 0,则没有 Masking-key。

备注:载荷数据的长度,不包含 mask key 的长度。

7)Payload data:(x+y) 字节

载荷数据: 包含了扩大数据、利用数据。其中,扩大数据 x 字节,利用数据 y 字节。

扩大数据: 如果没有协商应用扩大的话,扩大数据数据为 0 字节。所有的扩大都必须申明扩大数据的长度,或者能够如何计算出扩大数据的长度。此外,扩大如何应用必须在握手阶段就协商好。如果扩大数据存在,那么载荷数据长度必须将扩大数据的长度蕴含在内。

利用数据: 任意的利用数据,在扩大数据之后(如果存在扩大数据),占据了数据帧残余的地位。载荷数据长度 减去 扩大数据长度,就失去利用数据的长度。

7.4 掩码算法

掩码键(Masking-key)是由客户端筛选进去的 32 位的随机数。掩码操作不会影响数据载荷的长度。

掩码、反掩码操作都采纳如下算法。

首先,假如:

original-octet-i:为原始数据的第 i 字节;
transformed-octet-i:为转换后的数据的第 i 字节;
j:为 i mod 4 的后果;
masking-key-octet-j:为 mask key 第 j 字节。

算法形容为: original-octet-i 与 masking-key-octet-j 异或后,失去 transformed-octet-i。

j = i MOD 4
transformed-octet-i = original-octet-i XOR masking-key-octet-j

8、数据传输

一旦 WebSocket 客户端、服务端建设连贯后,后续的操作都是基于数据帧的传递。

WebSocket 依据 opcode 来辨别操作的类型。比方 0x8 示意断开连接,0x0-0x2 示意数据交互。

8.1 数据分片

WebSocket 的每条音讯可能被切分成多个数据帧。当 WebSocket 的接管方收到一个数据帧时,会依据 FIN 的值来判断,是否曾经收到音讯的最初一个数据帧。

FIN= 1 示意以后数据帧为音讯的最初一个数据帧,此时接管方曾经收到残缺的音讯,能够对音讯进行解决。FIN=0,则接管方还须要持续监听接管其余的数据帧。

此外,opcode 在数据交换的场景下,示意的是数据的类型。0x01 示意文本,0x02 示意二进制。而 0x00 比拟非凡,示意连续帧(continuation frame),顾名思义,就是残缺音讯对应的数据帧还没接管完。

8.2 数据分片例子

间接看例子更形象些。上面例子来自 MDN,能够很好地演示数据的分片。客户端向服务端两次发送音讯,服务端收到音讯后回应客户端,这里次要看客户端往服务端发送的音讯。

第一条音讯:

FIN=1, 示意是以后音讯的最初一个数据帧。服务端收到以后数据帧后,能够解决音讯。opcode=0x1,示意客户端发送的是文本类型。

第二条音讯:

  • 1)FIN=0,opcode=0x1,示意发送的是文本类型,且音讯还没发送实现,还有后续的数据帧;
  • 2)FIN=0,opcode=0x0,示意音讯还没发送实现,还有后续的数据帧,以后的数据帧须要接在上一条数据帧之后;
  • 3)FIN=1,opcode=0x0,示意音讯曾经发送实现,没有后续的数据帧,以后的数据帧须要接在上一条数据帧之后。服务端能够将关联的数据帧组装成残缺的音讯。

Client: FIN=1, opcode=0x1, msg=”hello”
Server: (process complete message immediately) Hi.
Client: FIN=0, opcode=0x1, msg=”and a”
Server: (listening, new message containing text started)
Client: FIN=0, opcode=0x0, msg=”happy new”
Server: (listening, payload concatenated to previous message)
Client: FIN=1, opcode=0x0, msg=”year!”
Server: (process complete message) Happy new year to you too!

9、连贯放弃、心跳

WebSocket 为了放弃客户端、服务端的实时双向通信,须要确保客户端、服务端之间的 TCP 通道放弃连贯没有断开。

然而,对于长时间没有数据往来的连贯,如果仍旧长时间放弃着,可能会节约包含的连贯资源。

但不排除有些场景,客户端、服务端尽管长时间没有数据往来,但仍须要放弃连贯。

这个时候,能够采纳心跳来实现:

发送方 -> 接管方:ping
接管方 -> 发送方:pong

ping、pong 的操作,对应的是 WebSocket 的两个管制帧,opcode 别离是 0x9、0xA。

举例:WebSocket 服务端向客户端发送 ping,只须要如下代码(采纳 ws 模块)

ws.ping(”, false, true);

10、Sec-WebSocket-Key/Accept 的作用

后面提到了,Sec-WebSocket-Key/Sec-WebSocket-Accept 在次要作用在于提供根底的防护,缩小歹意连贯、意外连贯。

作用大抵归纳如下:

  • 1)防止服务端收到非法的 websocket 连贯(比方 http 客户端不小心申请连贯 websocket 服务,此时服务端能够间接回绝连贯)
  • 2)确保服务端了解 websocket 连贯。因为 ws 握手阶段采纳的是 http 协定,因而可能 ws 连贯是被一个 http 服务器解决并返回的,此时客户端能够通过 Sec-WebSocket-Key 来确保服务端意识 ws 协定。(并非百分百保险,比方总是存在那么些无聊的 http 服务器,光解决 Sec-WebSocket-Key,但并没有实现 ws 协定。。。)
  • 3)用浏览器里发动 ajax 申请,设置 header 时,Sec-WebSocket-Key 以及其余相干的 header 是被禁止的。这样能够防止客户端发送 ajax 申请时,意外申请协定降级(websocket upgrade)
  • 4)能够避免反向代理(不了解 ws 协定)返回谬误的数据。比方反向代理前后收到两次 ws 连贯的降级申请,反向代理把第一次申请的返回给 cache 住,而后第二次申请到来时间接把 cache 住的申请给返回(无意义的返回)。
  • 5)Sec-WebSocket-Key 次要目标并不是确保数据的安全性,因为 Sec-WebSocket-Key、Sec-WebSocket-Accept 的转换计算公式是公开的,而且非常简单,最次要的作用是预防一些常见的意外状况(非故意的)。

强调:Sec-WebSocket-Key/Sec-WebSocket-Accept 的换算,只能带来根本的保障,但连贯是否平安、数据是否平安、客户端 / 服务端是否非法的 ws 客户端、ws 服务端,其实并没有实际性的保障。

11、数据掩码的作用

11.1 概述

WebSocket 协定中,数据掩码的作用是加强协定的安全性。但数据掩码并不是为了爱护数据自身,因为算法自身是公开的,运算也不简单。除了加密通道自身,仿佛没有太多无效的爱护通信安全的方法。

那么为什么还要引入掩码计算呢,除了减少计算机器的运算量外仿佛并没有太多的收益(这也是不少同学纳闷的点)。

答案还是两个字:平安。但并不是为了避免数据泄密,而是为了避免晚期版本的协定中存在的代理缓存净化攻打(proxy cache poisoning attacks)等问题。

11.2 代理缓存净化攻打

上面摘自 2010 年对于平安的一段讲话。其中提到了代理服务器在协定实现上的缺点可能导致的平安问题(点此查看出处)。

“We show, empirically, that the current version of the WebSocket consent mechanism is vulnerable to proxy cache poisoning attacks. Even though the WebSocket handshake is based on HTTP, which should be understood by most network intermediaries, the handshake uses the esoteric“Upgrade”mechanism of HTTP. In our experiment, we find that many proxies do not implement the Upgrade mechanism properly, which causes the handshake to succeed even though subsequent traffic over the socket will be misinterpreted by the proxy.”
【TALKING】Huang, L-S., Chen, E., Barth, A., Rescorla, E., and C.
Jackson, “Talking to Yourself for Fun and Profit”, 2010,

在正式形容攻打步骤之前,咱们假如有如下参与者:

  • 1)攻击者、攻击者本人管制的服务器(简称“邪恶服务器”)、攻击者伪造的资源(简称“邪恶资源”);
  • 2)受害者、受害者想要拜访的资源(简称“正义资源”);
  • 3)受害者理论想要拜访的服务器(简称“正义服务器”);
  • 4)两头代理服务器。

攻打步骤一:

  • 1)攻击者浏览器 向 邪恶服务器 发动 WebSocket 连贯。依据前文,首先是一个协定降级申请;
  • 2)协定降级申请 理论达到 代理服务器;
  • 3)代理服务器 将协定降级申请转发到 邪恶服务器;
  • 4)邪恶服务器 批准连贯,代理服务器 将响应转发给 攻击者。

因为 upgrade 的实现上有缺点,代理服务器 认为之前转发的是一般的 HTTP 音讯。因而,当协定服务器 批准连贯,代理服务器 认为本次会话曾经完结。

攻打步骤二:

  • 1)攻击者 在之前建设的连贯上,通过 WebSocket 的接口向 邪恶服务器 发送数据,且数据是精心结构的 HTTP 格局的文本。其中蕴含了 正义资源的地址,以及一个伪造的 host(指向正义服务器)。(见前面报文)
  • 2)申请达到 代理服务器。尽管复用了之前的 TCP 连贯,但 代理服务器 认为是新的 HTTP 申请。
  • 3)代理服务器 向 邪恶服务器 申请 邪恶资源。
  • 4)邪恶服务器 返回 邪恶资源。代理服务器 缓存住 邪恶资源(url 是对的,但 host 是 正义服务器 的地址)。

到这里,受害者能够退场了:

  • 1)受害者 通过 代理服务器 拜访 正义服务器 的 正义资源。
  • 2)代理服务器 查看该资源的 url、host,发现本地有一份缓存(伪造的)。
  • 3)代理服务器 将 邪恶资源 返回给 受害者。
  • 4)受害者 卒。

附: 后面提到的精心结构的“HTTP 申请报文”。

Client → Server:
POST /path/of/attackers/choice HTTP/1.1 Host: host-of-attackers-choice.com Sec-WebSocket-Key: <connection-key>
Server → Client:
HTTP/1.1 200 OK
Sec-WebSocket-Accept: <connection-key>

11.3 以后解决方案

最后的提案是对数据进行加密解决。基于平安、效率的思考,最终采纳了折中的计划:对数据载荷进行掩码解决。

须要留神的是,这里只是限度了浏览器对数据载荷进行掩码解决,然而好人齐全能够实现本人的 WebSocket 客户端、服务端,不按规定来,攻打能够照常进行。

然而对浏览器加上这个限度后,能够大大增加攻打的难度,以及攻打的影响范畴。如果没有这个限度,只须要在网上放个钓鱼网站骗人去拜访,一下子就能够在短时间内开展大范畴的攻打。

12、写在前面

WebSocket 可写的货色还挺多,比方 WebSocket 扩大。客户端、服务端之间是如何协商、应用扩大的。WebSocket 扩大能够给协定自身减少很多能力和设想空间,比方数据的压缩、加密,以及多路复用等。

篇幅所限,这里先不开展,感兴趣的同学能够留言交换。文章如有错漏,敬请指出。

13、参考资料

[1] RFC6455:websocket 标准
[2] 标准:数据帧掩码细节
[3] 标准:数据帧格局
[4] server-example
[5] 编写 websocket 服务器
[6] 对网络基础设施的攻打(数据掩码操作所要预防的事件)
[7] Talking to Yourself for Fun and Profit(含有攻打形容)
[8] What is Sec-WebSocket-Key for?
[9] 10.3. Attacks On Infrastructure (Masking)
[10] Talking to Yourself for Fun and Profit
[11] Why are WebSockets masked?
[12] How does websocket frame masking protect against cache poisoning?
[13] What is the mask in a WebSocket frame?

附录:更多 Web 端即时通讯材料

《SSE 技术详解:一种全新的 HTML5 服务器推送事件技术》
《Comet 技术详解:基于 HTTP 长连贯的 Web 端实时通信技术》
《socket.io 实现音讯推送的一点实际及思路》
《LinkedIn 的 Web 端即时通讯实际:实现单机几十万条长连贯》
《Web 端即时通讯技术的倒退与 WebSocket、Socket.io 的技术实际》
《Web 端即时通讯平安:跨站点 WebSocket 劫持破绽详解 (含示例代码)》
《开源框架 Pomelo 实际:搭建 Web 端高性能分布式 IM 聊天服务器》
《应用 WebSocket 和 SSE 技术实现 Web 端音讯推送》
《详解 Web 端通信形式的演进:从 Ajax、JSONP 到 SSE、Websocket》
《MobileIMSDK-Web 的网络层框架为何应用的是 Socket.io 而不是 Netty?》
《实践联系实际:从零了解 WebSocket 的通信原理、协定格局、安全性》
《微信小程序中如何应用 WebSocket 实现长连贯 (含残缺源码)》
《疾速理解 Electron:新一代基于 Web 的跨平台桌面技术》
《一文读懂前端技术演进:盘点 Web 前端 20 年的技术变迁史》
《Web 端即时通讯基础知识补课:一文搞懂跨域的所有问题!》
《Web 端即时通讯实际干货:如何让你的 WebSocket 断网重连更疾速?》
《WebSocket 从入门到精通,半小时就够!》
 更多同类文章 ……

(本文同步公布于:http://www.52im.net/thread-3134-1-1.html)

本文将同步公布于“即时通讯技术圈”公众号,欢送关注:

▲ 本文在公众号上的链接是:点此进入

正文完
 0