4

简介

ws模块是Node端的一个WebSocket协议的实现,该协议允许客户端(一般是浏览器)持久化和服务端的连接.

这种可以持续连接的特性使得WebScoket特别适合用于适合用于游戏或者聊天室等使用场景.

ws模块相较于其他基于WebSocket协议的模块来说非常的纯粹.
他只关注基于WebSocket协议的实现,其他例如Socket.io提供了回退手段,当WebSocket无法使用的时候会利用轮询来模拟持久化连接.

WebSocket协议被设计的十分简单且有效,没有了解过的朋友可以先了解一下,这里附上几个介绍WebSocket协议的文章.

https://developer.mozilla.org...
http://www.ruanyifeng.com/blo...
https://www.cnblogs.com/fuqia...

本文章主要分为如下几个部分:

  • ws模块介绍
  • ws搭建服务器
  • ws制作客户端
  • ws配合Vue制作一个简单在线的聊天室

本文章中使用的ws版本为6.1.0.

ws模块介绍

ws模块基本分为两个部分,有着如下的特点:

  • server部分

    • 使用ws模块可以配置进行流式传输
    • 基于现有的Http/s服务器进行建立连接
    • 基于内部的Http模块直接建立服务器
    • 手动控制协议的升级
  • client部分

    • 几乎和浏览器端一致API的客户端实现

引入ws模块:

const WebSocket = require('ws');

创建服务器:

const wss = new WebSocket.Server({
    port:8080
});

创建客户端:

const ws = new WebSocket('ws://127.0.0.1:8080');

ws服务器建立

ws服务器的建立可以基于一个Http服务器或者使用内部的Http服务器,为了简单介绍后面的例子一律使用内部服务器.

ws模块的服务端的创建和使用非常类似于Node的Http模块:

const WebSocket = require('ws');
 
const wss = new WebSocket.Server({ port: 8080 }); // 监听端口
 
wss.on('connection', function connection(ws) { // 当服务器和客户端握手成功后触发该事件,而第一个参数就是一个client对象
  ws.on('message', function incoming(message) {
    console.log('客户端发送的数据', message);
  });
 
  ws.send('something'); // 响应内容
});

这里需要指明的一点是,WebSocket是通过Http进行协议升级后为WebSocket协议的.

connection事件中第一个参数为一个Client对象实际上就是ws模块的客户端实例.
ws模块用这个对象来描述一个连接对象.
而第二个参数是一个http.IncomingMessage对象,可以利用他来获取请求参数例如Cookie.

这里大家只要记住connection事件的第一个参数是一个ws实例对象就可以了,后面会介绍这个对象.

Server端有很多事件和属性还有方法,这里我只写出了一些常见的参数,详细的官方文档我会添加在文章的末尾.

事件:

  • close 服务器关闭时候触发
  • connection 客户端和服务器握手完成后触发
  • error 服务器底层错误时候触发
  • headers 客户端请求升级协议的请求触发.这个时候还没有建立WebSocket通信,你可以在这个事件检查和修改Header
  • listening 服务器启动监听时候触发

属性:

  • server.clients 一个Set对象保存了服务器所有的已建立的连接对象,只有在Server的构造函数中clientTracking为True的时候才有效.

方法:

  • close() 调用后关闭内部的Http服务器,一旦数据传输完成后将自动关闭所有的客户端连接

客户端建立

上文中已经提到了ws模块提供的客户端API几乎和浏览器一致,确实如此,但是它提供了比浏览器端更加丰富的功能.

例子使用客户端(该例子来源于官网):

const WebSocket = require('ws');
 
const ws = new WebSocket('wss://echo.websocket.org/', {
  origin: 'https://websocket.org'
});
 
ws.on('open', function open() { // 握手成功后触发
  console.log('connected');
  ws.send(Date.now());
});
 
ws.on('close', function close() {
  console.log('disconnected');
});
 
ws.on('message', function incoming(data) { // 服务器信息到达时候触发
  console.log(`Roundtrip time: ${Date.now() - data} ms`);
 
  setTimeout(function timeout() {
    ws.send(Date.now());
  }, 500);
});

echo.websocket.org这个网站中提供了一个简单的webSocket的服务器,你可以直接在Node中运行上面这个例子.

同样的客户端也提供了丰富的事件属性和方法,这里简单的介绍了一些最常使用的内容:

  • 事件

    • close 连接关闭的时候触发.
    • error 底层错误的时候触发,例如服务器无应答导致的超时.
    • message 服务器发送数据到达的时候触发
    • open 当服务器建立连接的时候触发
  • 方法

    • addEventListener
    • removeEventListener
    • send 用于向服务器发送数据
    • close 关闭连接(当所本次数据接收或者发送完成后)
    • terminate 直接关闭连接
  • 属性

    • readyState 当前连接的状态 一共四个值 0 连接中 1 打开 3 关闭中 4 关闭 (和浏览器端的状态码完全一致)

实例

服务器和客户端交互

const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws) {

    ws.on('message', function incoming(message) {
        console.log('服务器接受到客户端传送的内容:', message);
    });

    // 服务器发送的数据
    ws.send('这是服务器发送的数据');

});

const ws = new WebSocket('ws://127.0.0.1:8080');

ws.on('open', function open() {
    // 客户端发送的数据
    ws.send('我是客户端');
});

ws.on('message', function incoming(data) {

    // 接受到服务端发送的数据
    console.log('客户端接受到服务器的内容',data);

});

输出:

客户端接受到服务器的内容 这是服务器发送的数据
服务器接受到客户端传送的内容: 我是客户端

广播消息

广播消息的基本原理就是获取服务器在connection事件中传入的client对象,然后client对象都收集起来,然后迭代调用send方法.

官方的例子:

const WebSocket = require('ws');
 
const wss = new WebSocket.Server({ port: 8080 });
 
// 给服务器对象上挂载一个广播的方法,向所有人广播
wss.broadcast = function broadcast(data) {

  // 获取服务器所有的连接然后迭代
  wss.clients.forEach(function each(client) {
  
    // 如果连接是打开状态
    if (client.readyState === WebSocket.OPEN) {
      // 发送消息
      client.send(data);
    }
  });
  
};
 
wss.on('connection', function connection(ws) {

  ws.on('message', function incoming(data) {
    // 迭代服务器中的所有的客户端对象
    wss.clients.forEach(function each(client) {
      // 如果连接状态是打开状态,且不是当前客户端对象
      if (client !== ws && client.readyState === WebSocket.OPEN) {
        // 发送消息
        client.send(data);
      }
    });
  });
});

浏览器端和服务器交互

服务器:

const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws) {

    ws.on('message', function incoming(message) {
        console.log('服务器接受到客户端传送的内容:', message);
    });

    // 服务器发送的数据
    ws.send('这是服务器发送的数据');

});

浏览器:

const client = new WebSocket('ws://127.0.0.1:8080');

client.addEventListener('open',()=>{
    // 客户端发送的数据
    client.send('我是客户端');
});

client.addEventListener('message',(data)=>{
     // 接受到服务端发送的数据
    console.log('客户端接受到服务器的内容', data);
});
浏览器客户端和ws客户端异同
特性 浏览器 ws客户端
使用on方法添加事件 不可以 可以
使用addEventListener 可以 可以
使用onerror,onclose... 可以 可以
message事件,evnt.data获取数据
readyState属性

使用Vue+ws来制作一个在线聊天室

代码已放到github:

https://github.com/uioz/Simpl...

注意:没有使用构建工具.

注意:该项目服务器部分是使用TS编写的,但是客户端没有使用TS.

引用

npm指引包含:

  • 二进制数据的传输和压缩.
  • 外部Http/s服务器升级为WebSocket的具体使用方式.
  • 一个Http对应多个WebSocketServer
  • 心跳超时检测.
  • 客户端ip获取
https://www.npmjs.com/package/ws

API手册:

https://github.com/websockets...

ASCll
527 声望13 粉丝