简介
ws模块是Node端的一个WebSocket协议的实现,该协议允许客户端(一般是浏览器)持久化和服务端的连接.
这种可以持续连接的特性使得WebScoket特别适合用于适合用于游戏或者聊天室等使用场景.
ws模块相较于其他基于WebSocket协议的模块来说非常的纯粹.
他只关注基于WebSocket协议的实现,其他例如Socket.io
提供了回退手段,当WebSocket无法使用的时候会利用轮询来模拟持久化连接.
WebSocket协议被设计的十分简单且有效,没有了解过的朋友可以先了解一下,这里附上几个介绍WebSocket协议的文章.
https://developer.mozilla.org…
本文章主要分为如下几个部分:
- 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:
注意:没有使用构建工具.
注意:该项目服务器部分是使用TS编写的,但是客户端没有使用TS.
引用
npm指引包含:
- 二进制数据的传输和压缩.
- 外部Http/s服务器升级为WebSocket的具体使用方式.
- 一个Http对应多个WebSocketServer
- 心跳超时检测.
- 客户端ip获取
API手册: