本文原题“Node.js - 200 多行代码实现 Websocket 协定”,为了晋升内容品质,有较大订正。

1、引言

最近正在钻研 WebSocket 相干的常识,想着如何能本人实现 WebSocket 协定。到网上收罗了一番材料后用 Node.js 实现了一个WebSocket协定服务器,倒也没有设想中那么简单,除去正文语句和 console 语句后,大概 200 行代码左右。

本文分享了自已开发一个WebSocket服务端实现过程中须要的常识储备,以及具体的代码实现含意等,非常适合想在短时间内对WebSocket协定从入门到精通的Web端即时通讯开发者浏览。

如果你想要写一个WebSocket 服务器,首先须要读懂对应的网络协议 RFC6455,不过这对于个别人来说有些 “艰涩”,英文且不说,还得咬文嚼字了解 网络编程 含意。

好在 WebSocket 技术呈现比拟早,所以早就有人翻译了残缺的 RFC6455中文版,网上也有很多针对该协定的分析文章,很多文章里还有现成的实现代码能够参考,所以说实现一个简略的 WebSocket 服务并非难事。

本文更偏差实战(in action),会从常识储备、具体代码剖析以及注意事项角度去解说如何用 Node.js 实现一个简略的 WebSocket 服务,至于 WebSocket 概念、定义、解释和用处等基础知识不会波及,因为这些常识在本文所列的参考文章中轻松找到。

情谊提醒:本文对应的源码,请从文末“11、代码下载”一节下载之。

学习交换:

  • 即时通讯技术交换群:215477170 [举荐]
  • 挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》
  • 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

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

2、对于作者

  • 作者网名:JSCON简时空
  • 作者微博:https://weibo.com/271111536
  • 博客地址:https://segmentfault.com/u/jscon
  • Github主页:https://boycgit.github.io/

3、基本常识

在学习本文内容之前,我认为很有必要简略理解一下Web端即时通讯技术的“过来”和“当初”,因为新时代的开发者(没有经验过短轮询、长轮询、Comet技术的这波人),很难了解WebSocket对于Web端的即时通讯技术来说,意味着什么。

所谓“忆苦思甜”,理解了Web端即时通讯技术的过来,方知WebSocket这种技术的宝贵。。。

3.1 旧时代的Web端即时通讯技术

自从Web端即时通讯的概念提出后,“实时”性便成为了Web开发者们津津有味的话题。实时化的Web利用,凭借其响应迅速、无需刷新、节俭网络流量的个性,不仅让开发者们眼前一亮,更是为用户带来绝佳的网络体验。

但很多开发者可能并不分明,旧时代的Web端“实时”通信,次要基于 Ajax的拉取和Comet的推送。

大家都晓得Ajax,这是一种借助浏览器端JavaScript实现的异步无刷新申请性能:要客户端按需向服务器发出请求,并异步获取来自服务器的响应,而后依照逻辑更新以后页面的相应内容。

然而这仅仅是拉取啊,这并不是真正的“实时”:短少服务器端的主动推送!

因而,咱们不得不应用另一种略简单的技术 Comet,只有当这两者配合起来,这个Web利用才勉强算是个“实时”的Web端利用!

▲ Ajax和Comet技术原理(图片援用自《Web端即时通讯技术盘点》)

3.2 WebSocket协定呈现

随着HTML5规范的呈现,WebSocket技术横空出世,随着HTML5规范的宽泛遍及,越来越多的古代浏览器开始全面反对WebSocket技术了。

至于WebSocket,我想大家或多或少都据说过。

WebSocket是一种全新的协定。它将TCP的Socket(套接字)利用在了web page上,从而使通信单方建设起一个放弃在活动状态连贯通道,并且属于全双工(单方同时进行双向通信)。

事实是:WebSocket协定是借用HTTP协定的 _101 switch protocol_ 来达到协定转换的,从HTTP协定切换成WebSocket通信协议。

再简略点来说,它就如同将 Ajax 和 Comet 技术的特点联合到了一起,只不过性能要高并且应用起来要不便的多(不便当然是之指在客户端方面了)。

4、WebSocket常识储备

如果要本人写一个 WebSocket 服务,次要有两个难点:

  • 1)熟练掌握 WebSocket 的协定,这个须要多读现有的解读类文章(上面会给出参考文章);
  • 2)操作二进制数据流,在 Node.js 中须要对 Buffer 这个类略微相熟些。

同时还须要具备两个根底知识点:

  • 1)网络编程中应用 大端字节序 示意大于一字节的数据,称之为 网络字节序 (不知道大小端的,举荐浏览《史上最艰深大小端字节序详解》);
  • 2)理解最高无效位(MSB, Most Significant Bit),不太分明的,能够参考《LSB最低无效位和MSB最高无效位》。

具体的做法如下,举荐先浏览以下几篇参考文章:

  • 1)《学习WebSocket协定—从顶层到底层的实现原理(修订版)》:作者自身就用Node.js实现过一遍,知识点解说挺透彻,适宜优先浏览;
  • 2)《WebSocket详解(一):初步意识WebSocket技术》:是一系列的文章,从浅入深,配有丰盛的图文;
  • 3)《WebSocket从入门到精通,半小时就够!》:全文以Q&A模式组织,要点都解读到了,还波及了建设连贯、替换数据、帧格局及网络安全等;
  • 4)《MDN - Writing WebSocket servers》:MDN 官网教程,读一遍没啥害处。

而后开始写代码。

在实现过程中的大部分代码能够从上面几篇文章中找到并借鉴(copy):

  • 1)nodejs 实现:简化版本的从这儿借鉴过去的;
  • 2)学习WebSocket协定—从顶层到底层的实现原理(修订版)。

浏览完下面的文章,你会有发现一个共同点,就是在实现 WebSockets 过程中,最最外围的局部就是 解析 或者 生成 Frame(帧)。

就是上面这构造:

▲ 截图来自《rfc6455 - Base Framing Protocol》

想要了解 frame 各个字段的含意,可参考《WebSocket详解(三):深刻WebSocket通信协议细节》,文中作者绘制了一副图来解释这个 frame 构造。

而在代码层面,frame 的解析或生成能够在 RocketEngine - parser 或者 __processBuffer_ 中找到。

在实现下面几个方面的常识储备之后,而且大多有现成的代码,所以本人边抄边写一个 Websocket 服务端实现并不算太难。

对于 WebSocket 初学者,请务必浏览以上参考文章,对 Websocket 协定有大略的理解之后再持续本文剩下局部的浏览,否则很有可能会感觉我写得云里雾里,不知所云。

5、实战成果预览

本次的实现代码能够从文末“11、代码下载”章节下载到:

(请从原文链接下载:http://www.52im.net/thread-31...)

下载后本地运行即可,执行:

node index.js

运行胜利后,将会在 http://127.0.0.1:3000 创立服务。

运行服务之后,关上控制台就能看到成果:

动图中浏览器 console 所执行的 js 代码步骤如下:

1)先建设连贯:

var ws = new WebSocket("ws://127.0.0.1:3000");
ws.onmessage = function(evt) {
  console.log( "Received Message: "+ evt.data);
};

_2)而后发送音讯:_(留神肯定要在建设连贯之后再执行该语句,否则发不出音讯的)

ws.send('hello world');

从成果可见,咱们曾经实现 WebSocket 最根本的通信性能了。

接下来咱们具体看一下具体实现的细节。

6、代码解读1:调用所写的 WebSocket 类

站在使用者的角度,假如咱们曾经实现 WebSocket 类了,那么应该怎么应用?

客户端通过 HTTP Upgrade 申请,即 _101 Switching Protocol_ 到 HTTP 服务器,而后由服务器进行协定转换。

在 Node.js 中咱们通过 http.createServer 获取 http.server 实例,而后监听 upgrade 事件,在解决这个事件。

如上面的代码所示:

// HTTP服务器局部
var server = http.createServer(function(req, res) {
  res.end('websocket testrn');
});
// Upgrade申请解决
server.on('upgrade', function(req, socket, upgradeHead){
  // 初始化 ws
  var ws = new WebSocket(req, socket, upgradeHead);
  // ... ws 监听 data、error 的逻辑等
});

这里监听 upgrade 事件的回调函数中第二个参数 _socket_ 是 net.Socket实例,这个类是 TCP 或 UNIX Socket 的形象,同时一个 net.Socket 也是一个 duplex stream,所以它能被读或写,并且它也是一个 EventEmitter。

咱们就利用这个 socket 对象上进行 Websocket 类实例的初始化工作;

7、代码解读2:构造函数

所以不难理解 Websocket 的构造函数就是上面这个样子:

class WebSocket extends EventEmitter {
  constructor(req, socket, upgradeHead){
    super(); // 调用 EventEmitter 构造函数
    // 1. 结构响应头 resHeaders 局部
    // 2. 监听 socket 的 data 事件,以及 error 事件
    // 3. 初始化成员属性
  }
}

留神:咱们须要继承内置的 EventEmitter ,这样生成的实例能力监听、绑定事件。

Node.js 采纳事件驱动、异步编程,天生就是为了网络服务而设计的,继承 EventEmitter 就能享受到非阻塞模式的 IO 解决。

这里特地讲一下其中 响应头的结构 和 事件监听 局部。

7.1 返回响应头(Response Header)

依据协定标准,咱们能写出响应头的内容:

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

具体代码如下:

var resKey = hashWebSocketKey(req.headers['sec-websocket-key']);
// 结构响应头
var resHeaders = [
  'HTTP/1.1 101 Switching Protocols',
  'Upgrade: websocket',
  'Connection: Upgrade',
  'Sec-WebSocket-Accept: '+ resKey
]
  .concat('', '')
  .join('rn');
socket.write(resHeaders);

当执行 _socket.write(resHeaders);_ 到后就和客户端建设起 WebSocket 连贯了,剩下去就是数据的解决。

7.2 监听事件

_socket_ 就是 TCP 协定的形象,间接在下面监听已有的 _data_ 事件和 _close_ 事件这两个事件。

还有其余事件,比方 error、end 等,具体参考 net.Socket 文档。

socket.on('data', data => {
  this.buffer = Buffer.concat([this.buffer, data]);
  while(this._processBuffer()) {} // 循环解决返回的 data 数据
});
socket.on('close', had_error => {
  if(!this.closed) {
    this.emit('close', 1006);
    this.closed = true;
  }
});

_close_ 的事件逻辑比较简单,比拟重要的是 _data_ 的事件监听局部。外围就是 _this._processBuffer()_ 这个办法,用于解决客户端传送过去的数据(即 Frame 数据)。

留神:该办法是放在 _while_ 循环语句里,解决好边界状况,避免死循环。

8、代码解读3:Frame 帧数据的解决

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

这 this._processBuffer() 局部代码逻辑就是用来解析帧数据的,所以它是实现 WebSocket 代码的要害;(该办法外面用到了大量的位操作符以及 Buffer 类的操作)

帧数据结构具体定义可参考 RFC6455 5.2节(英文不好的话,去下载中文翻译版《WebSocket标准协议手册(稀缺中文版+英文原版)》),下面列举的参考文章都有具体的解读,我在这儿也不啰嗦讲细节了,间接看代码比听我用文字讲要好。

这里就其中两个细节须要铺垫一下,不便更好地了解代码。

8.1 操作码(Opcode)

Opcode 即 操作代码,Opcode 的值决定了应该如何解析后续的数据载荷(data payload)

依据 Opcode 咱们能够大抵将数据帧分成两大类:数据帧 和 管制帧。

数据帧,目前只有 3 种,对应的 opcode 是:

  • 0x0:数据连续帧
  • 0x1:utf-8文本
  • 0x2:二进制数据;
  • 0x3 - 0x7:目前保留,用于后续定义的非管制帧。

管制帧,除了上述 3 种数据帧之外,剩下的都是管制帧:

  • 0x8:示意连贯断开
  • 0x9:示意 ping 操作
  • 0xA:示意 pong 操作
  • 0xB - 0xF:目前保留,用于后续定义的管制帧

在代码里,咱们会先从帧数据中提取操作码:

var opcode = byte1 & 0x0f; //截取第一个字节的后 4 位,即 opcode 码

而后依据协定获取到真正的数据载荷(data payload),而后将这两局部传给 _handleFrame 办法:

this._handleFrame(opcode, payload); // 解决操作码

该办法会依据不同的 opcode 做出不同的操作:

_handleFrame(opcode, buffer) {
    var payload;
    switch(opcode) {
      case OPCODES.TEXT:
        payload = buffer.toString('utf8'); //如果是文本须要转化为utf8的编码
        this.emit('data', opcode, payload); //Buffer.toString()默认utf8 这里是成心批示的
        break;
      case OPCODES.BINARY: //二进制文件间接交付
        payload = buffer;
        this.emit('data', opcode, payload);
        break;
      case OPCODES.PING: // 发送 pong 做响应
        this._doSend(OPCODES.PONG, buffer);
        break;
      case OPCODES.PONG: //不做解决
        console.log('server receive pong');
        break;
      case OPCODES.CLOSE: // close有很多敞开码
        let code, reason; // 用于获取敞开码和敞开起因
        if(buffer.length >= 2) {
          code = buffer.readUInt16BE(0);
          reason = buffer.toString('utf8', 2);
        }
        this.close(code, reason);
        this.emit('close', code, reason);
        break;
      default:
        this.close(1002, 'unhandle opcode:'+ opcode);
    }
  }

8.2 分片(Fragment)

本节代码对应的规范文档:5.4 - Fragmentation(英文不好的话,去下载中文翻译版《WebSocket标准协议手册(稀缺中文版+英文原版)》)。

一旦 WebSocket 客户端、服务端建设连贯后,后续的操作都是基于数据帧的传递。实践上来说,每个帧(Frame)的大小是没有限度的。

对于大块的数据,WebSocket 协定倡议对数据进行分片(Fragment)操作。

分片的意义次要是两方面:

  • 1)次要目标是容许当音讯开始但不用缓冲该音讯时发送一个未知大小的音讯。如果音讯不能被分片,那么端点将不得不缓冲整个音讯以便在首字节产生之前统计出它的长度。对于分片,服务器或中间件能够抉择一个适合大小的缓冲,当缓冲满时,再写一个片段到网络;
  • 2)另一方面分片传输也能更高效地利用多路复用进步带宽利用率,一个逻辑通道上的一个大音讯独占输入通道是不可取的,因而多路复用须要能够宰割音讯为更小的分段来更好的共享输入通道。参考文档《I/O多路复用(multiplexing)是什么?》。

WebSocket 协定提供的分片办法,是将本来一个大的帧拆分成数个小的帧。

上面是把一个大的Frame分片的图示:

由图可知,第一个分片的 _FIN_ 为 0,Opcode 为非0值(0x1 或 0x2),最初一个分片的FIN为1,Opcode为 0。两头分片的 _FIN_ 和 _opcode_ 二者均为 0。

依据 FIN 的值来判断,是否曾经收到音讯的最初一个数据帧:

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

opcode在数据交换的场景下,示意的是数据的类型:

  • 1)0x01 示意文本,永远是 utf8 编码的;
  • 2)0x02 示意二进制;
  • 3)0x00 比拟非凡,示意 连续帧(continuation frame),顾名思义,就是残缺音讯对应的数据帧还没接管完。

代码里,咱们须要检测 _FIN_ 的值,如果为 0 阐明有分片,须要记录第一个 FIN 为 0 时的 _opcode_ 值,缓存到 _this.frameOpcode_ 属性中,将载荷缓存到 this.frames 属性中。

如下所示:

var FIN = byte1 & 0x80; // 如果为0x80,则标记传输完结,获取高位 bit
// 如果是 0 的话,阐明是连续帧,须要保留好 opCode
if(!FIN) {
  this.frameOpcode = opcode || this.frameOpcode; // 确保不为 0;
}
//....
// 有可能是分帧,须要拼接数据
this.frames = Buffer.concat([this.frames, payload]); // 保留到 frames 中

当接管到最初一个 FIN 帧的时候,就能够组装后给 _handleFrame 办法:

if(FIN) {
  payload = this.frames.slice(0); // 获取所有拼接残缺的数据
  opcode = opcode || this.frameOpcode; // 如果是 0 ,则放弃获取之前保留的 code
  this.frames = Buffer.alloc(0); // 清空 frames
  this.frameOpcode = 0; // 清空 opcode
  this._handleFrame(opcode, payload); // 解决操作码
}

8.3 发送数据帧

下面讲的都是接管并解析来自客户端的数据帧,当咱们想给客户端发送数据帧的时候,也得按协定来。

这部分操作相当于是上述 __processBuffer_ 办法的逆向操作,在代码里咱们应用 _encodeMessage_ 办法(为了简略起见,咱们发送给客户端的数据没有通过掩码解决)将发送的数据分装成数据帧的格局,而后调用 _socket.write_ 办法发送给客户端。

如下所示:

_doSend(opcode, payload) {
  // 1. 思考数据分片
  this.socket.write(
    encodeMessage(count > 0 ? OPCODES.CONTINUE : opcode, payload)
  ); //编码后间接通过socket发送

为了思考分片场景,特意设置 MAX_FRAME_SIZE 来对每次发送的数据长度做截断做分片:

  // ...
  var len = Buffer.byteLength(payload);
  // 分片的间隔逻辑
  var count = 0;
  // 这里能够针对 payload 的长度做分片
  while(len > MAX_FRAME_SIZE) {
    var framePayload = payload.slice(0, MAX_FRAME_SIZE);
    payload = payload.slice(MAX_FRAME_SIZE);
    this.socket.write(
      encodeMessage(
        count > 0 ? OPCODES.CONTINUE : opcode,
        framePayload,
        false
      )
    ); //编码后间接通过socket发送
    count++;
    len = Buffer.byteLength(payload);
  }
// ...

至此曾经实现 WebSocket 协定的要害局部,所组装起来的代码就能和客户端建设 WebSocket 连贯并进行数据交互了。

9、无关WebSocket的常见疑难

9.1 字符串 “258EAFA5-E914-47DA-95CA-C5AB0DC85B11” 怎么来的?

这个标志性字符串是专门标示 _WebSocket_ 协定的 UUID;UUID 是长度为 16-byte(128-bit)的ID,个别以形如_f81d4fae-7dec-11d0-a765-00a0c91e6bf6_的字符串作为 URN(Uniform Resource Name,对立资源名称)。

UUID 能够移步到《UUID原理》和 RFC 4122 获取更多常识。

为啥抉择这个字符串?

在WebSocket标准协议文档的第七页曾经有明确的阐明了:

(英文不好的话,见中文翻译版《WebSocket标准协议手册(稀缺中文版+英文原版)》)

之所以选用这个 UUID ,次要该 ID 极大不太可能被其余不理解 WebSocket 协定的网络终端所应用。

我也不知道该怎么翻译。总之,就说这个 ID 就相当于 _WebSocket_ 协定的 “身份证号” 了。

9.2 Websocket 和 HTTP 什么关系?

HTTP、WebSocket 等应用层协定,都是基于 TCP 协定来传输数据的,咱们能够把这些高级协定了解成对 TCP 的封装。

既然大家都应用 TCP 协定,那么大家的连贯和断开,都要遵循 TCP 协定中的三次握手和四次握手 ,只是在连贯之后发送的内容不同,或者是断开的工夫不同。

对于 WebSocket 来说,它必须依赖 HTTP 协定进行一次握手 ,握手胜利后,数据就间接从 TCP 通道传输,与 HTTP 无关了。

更具体的解释,能够移步:

  • 《WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)》
  • 《WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)》
  • 《WebSocket详解(六):刨根问底WebSocket与Socket的关系》

9.3 浏览器中 Websocket 会主动分片么?

答案是:看具体浏览器的实现。

WebSocket是一个 message based 的协定,它能够主动将数据分片,并且主动将分片的数据组装。每个 message 能够是一个或多个分片。message 不记录长度,分片才记录长度。

依据协定 websocket 协定中帧长度下限为 2^63 byte(为 8388608 TB),能够认为没有限度,很显著按协定的最大下限来传输数据是不靠谱的。所以在理论应用中 _websocket_ 音讯长度限度取决于具体的实现。

对于这方面,找了两篇参考文章:

  • 1)《WebSocket须要像TCP Socket那样进行逻辑数据包的分包与合包吗?》:WebSocket是一个message-based的协定,它能够主动将数据分片,并且主动将分片的数据组装;;
  • 2)《websocket长文本问题?》:这里给出了长文本 ws 传输实际总结。

在文章《WebSocket探秘》中,作者就做了一个试验,作者发送 27378 个字节,后果被迫分包了;如果是大数据量,就会被socket主动分包发送。

而通过我自己试验,发现 Chrome 浏览器(版本 68.0.3440.106 - 64bit)会针对 131072(=2^17)bytes 大小进行主动分包。

我是通过以下测试代码验证:

var ws = new WebSocket("ws://127.0.0.1:3000");
ws.onmessage = function(evt) {
  console.log( "Received Message: "+ evt.data);
};
var myArray = new ArrayBuffer(131072 * 2 + 1);
ws.send(myArray);

服务端日志:

server detect fragment, sizeof payload: 131072
server detect fragment, sizeof payload: 131072
receive data: 2 262145

客户端日志:

Received Message: good job

截图如下:

而以同样的形式去测试一些本人机器上的浏览器:

  • 1)Firefox(62.0,64bit);
  • 2)safari (11.1.2 - 13605.3.8);
  • 3)IE 11。

这些客户端上的 WebSocket 简直没有大小的分片(随着数据量增大,发送会减缓,但并没有发现分片景象)。

10、本文小结

从刚开始决定浏览 WebSocket 协定,到本人应用 Node.js 实现一套简略的 WebSocket 协定,到这篇文章的产出,前后消耗大概 1 个月工夫(迁延症。。。)。

感激文中所提及的参考文献所给予的帮忙,让我实现过程中事倍功半。

之所以可能应用较少的代码实现 WebSocket,是因为 Node.js 体系自身了很好的根底,比方其所提供的 _EventEmitter_ 类自带事件循环,http 模块让你间接应用封装好的 _socket_ 对象,咱们只有依照 WebSocket 协定实现 Frame(帧)的解析和组装即可。

在实现一遍 WebSocket 协定后,就能较为粗浅地了解以下知识点(一切都是那么自然而然):

  • 1)Websocket 是一种应用层协定,是为了提供 Web 应用程序和服务端全双工通信而专门制订的;
  • 2)WebSocket 和 HTTP 都是基于 TCP 协定实现的;
  • 3)WebSocket和 HTTP 的惟一关联就是 HTTP 服务器须要发送一个 “Upgrade” 申请,即 101 Switching Protocol 到 HTTP 服务器,而后由服务器进行协定转换。
  • 4)WebSocket应用 HTTP 来建设连贯,然而定义了一系列新的 header 域,这些域在 HTTP 中并不会应用;
  • 5)WebSocket 能够和 HTTP Server 共享同一 port
  • 6)WebSocket 的 数据帧有序
  • ...

本文仅仅是协定的简略实现,对于 WebSocket 的其实还有很多事件能够做(比方反对 命名空间、流式 API 等),有趣味的能够参考业界风行的 WebSocket 仓库,去练习锻造一个强壮的 WebSocket 工具库轮子。

比方上面这些:

  • 1)socketio/socket.io:43.5k star,不多说,业界权威龙头老大。(不过这实际上不是一个 WebSocket 库,而是一个实时 pub/sub 框架。简略地说,Socket.IO 只是蕴含 WebSocket 性能的一个框架,如果要应用该库作为 server 端的服务,则 client 也必须应用该库,因为它不是规范的 WebSocket 协定,而是基于 WebSocket 再包装的音讯通信协议)
  • 2)websockets/ws:9k star,弱小易用的 websocket 服务端、客户端实现,还有提供很多弱小的个性
  • 3)uNetworking/uWebSockets:9.5k star,玲珑高性能的 WebSocket实现,C++ 写的,想更多理解 WebSocket 的底层实现,该库是不错的案例。
  • 4)theturtle32/WebSocket-Node:2.3k star,大部分应用 JavaScript,性能要害局部应用 C++ node-gyp 实现的库。其所列的 测试用例 有挺好的参考价值。

11、代码下载

(因无奈上传源码附件,如有须要,请从此链接下载:http://www.52im.net/thread-31...)

12、参考资料

[1]《新手入门贴:史上最全Web端即时通讯技术原理详解》
[2]《Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE》
[3]《SSE技术详解:一种全新的HTML5服务器推送事件技术》
[4]《Comet技术详解:基于HTTP长连贯的Web端实时通信技术》
[5]《老手疾速入门:WebSocket扼要教程》
[6]《WebSocket详解(一):初步意识WebSocket技术》
[7]《WebSocket详解(二):技术原理、代码演示和利用案例》
[8]《WebSocket详解(三):深刻WebSocket通信协议细节》
[9]《WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)》
[10]《WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)》
[11]《WebSocket详解(六):刨根问底WebSocket与Socket的关系》
[12]《Web端即时通讯技术的倒退与WebSocket、Socket.io的技术实际》
[13]《应用WebSocket和SSE技术实现Web端音讯推送》
[14]《详解Web端通信形式的演进:从Ajax、JSONP 到 SSE、Websocket》
[15]《MobileIMSDK-Web的网络层框架为何应用的是Socket.io而不是Netty?》
[16]《实践联系实际:从零了解WebSocket的通信原理、协定格局、安全性》
[17]《微信小程序中如何应用WebSocket实现长连贯(含残缺源码)》
[18]《八问WebSocket协定:为你疾速解答WebSocket热门疑难》
[19]《Web端即时通讯实际干货:如何让你的WebSocket断网重连更疾速?》
[20]《WebSocket从入门到精通,半小时就够!》

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

本文已公布在“即时通讯技术圈”公众号,欢送关注:

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