Last updated on 8 months ago
什么是 WebSocket
WebSocket 是一种网络传输协议。在传统模式中,客户端实现实时推送需要通过轮询(每个一段时间发起一次请求),而 WebSocket 就是为了解决这个问题而诞生,WebSocket 的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话
node.js 搭建 WebSocket 服务端
1
| const WebSocket = require("ws");
|
下面是个简单的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const WebSocket = require("ws");
const wss = new WebSocket.WebSocketServer({ port: 8080 });
wss.on("connection", function connection(ws) { console.log("New connection");
ws.on("message", (message) => { console.log(`[Client]: ${message}`); ws.send("ok"); });
ws.on("close", () => { console.log("Disconnected"); }); });
|
然后在终端输入
启动服务器
客户端连接
如果想在浏览器中连接客户端,js 原生支持 WebSocket,也可以使用 sockeio 或其他的库。如果想要在 node 中以终端的形式运行,也可以继续使用上面的 ws
这里先讲在 node 下运行服务端
新建一个 client.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const WebSocket = require("ws");
ws = new WebSocket("ws://localhost:8080");
ws.on("open", function () { ws.send("ok?"); });
ws.on("message", function (message) { console.log(`[SERVER]:${message}`); });
|
终端输入命令运行
如果要在浏览器中连接,可以直接用原生的 WebSocket
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <head> <title>WebSocket连接</title> </head> <body> <input id="input" type="text" /> <button onclick="send()">发送消息</button> </body> <script> let ws = new WebSocket("ws://localhost:8080");
ws.onopen = () => { console.log("连接成功"); };
ws.onmessage = (message) => { console.log(message.data); };
function send() { let message = document.getElementById("input").value; ws.send(message); } </script>
|
制作一个简单的聊天室
服务端 index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| const WebSocket = require("ws");
var clients = [];
const wss = new WebSocket.Server({ port: 8080 });
wss.on("connection", function connection(ws, req) { console.log("New connection");
ws.on("message", (message) => { console.log("Received: %s", message); if (String(message).startsWith("[username]")) { const index = clients.findIndex((client) => client.ws === ws); if (index != -1) { clients[index].name = message; } else { const username = message.slice(10); clients.push({ ws, username }); } } else { let index = clients.findIndex((client) => client.ws == ws); let username = clients[index].username; clients.forEach((client) => { if (client.ws !== ws) { client.ws.send(` [${username}]:${message}`); } }); } });
ws.on("close", function () { const index = clients.findIndex((client) => client.ws === ws); console.log(`[${clients[index].username}]Disconnected`); clients.splice(index, 1); }); });
|
客户端 client.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| const WebSocket = require("ws"); const readline = require("readline");
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
function connect(name) { const ws = new WebSocket("ws://localhost:8080");
ws.on("open", () => { console.log("连接成功"); ws.send(`[username]${name}`); });
ws.on("message", (message) => { console.log("收到消息:%s", message); });
function send() { rl.question("发送:", (message) => { ws.send(message); send(); }); }
send(); }
rl.question("你的名字:", (name) => { connect(name); });
|
打开三个终端,启动一次 index.js 和两个 client.js
1 2 3
| node idnex.js node client.js node client.js
|
在输入名字后就可以发送和接收消息了
原生 WebSocket 简单语法
只讲一些常用、简单的内容,具体内容请参考官方文档
WebSocket
对象提供了用于创建和管理 WebSocket
连接,以及可以通过该连接发送和接收数据的 API。
构造函数
1
| var aWebSocket = new WebSocket(url[, protocols]);
|
实例属性
binaryType
WebSocket.binaryType
返回 websocket 连接所传输二进制数据的类型
- 返回值
返回一串 String - “blob”:传输的是 blob 类型的数据 - “arraybuffer”:传输的是 ArrayBuffer 类型的数据
bufferedAmount
WebSocket.bufferedAmount
是一个只读属性,用于返回已经被send()
方法放入队列但还没有发送的数据的字节数,当全部数据被发送完后就会被重置为 0,如果传输中途连接中断则不会重置
readyState
WebSocket.readyState
是一个只读属性,返回 WebSocket 的链接状态
- 返回值
0-3 的数字用于表示不同的状态
- 0(WebSocket.CONNETION):正在连接中
- 1(WebSocket.OPEN):已经连接并且可以通讯
- 2(WebSocket.CLOSE):连接正在关闭
- 3(WebSocket.CLOSED):连接已经关闭或连接没有成功
url
WebSocket.url
是一个只读属性,返回构造函数创建WebSocket
实例对象时URL的绝对路线
实例方法
close()
WebSocket.close([code][,reason])
关闭连接
- 参数
- 可选
code
:一个数字状态码,解释了连接关闭的原因,不传默认1005(表示没有收到预期的状态码),其他状态码可以查看官方文档
- 可选
reason
:一个人类可读的字符串,解释连接关闭的原因,这个UTF-8编码的字符串不能超过123个字节
- 抛出异常
INVALID_ACCESS_ERR
:一个无效的code
SYNTAX_ERR
:reason字符串太长
send()
WebSocket.send(data)
,将 需要发送的数据 添加到队列中,并根据所需要传输的data bytes的大小自行增加bufferedAmount
的值。
- 参数
data
:传输至服务器的数据,必须是以下类型
- USVString:文本字符串
- ArrayBuffer:类型化数组对象发送底层二进制数据
- Blob:Blob 类型将队列 blob 中的原始数据以二进制中传输
- ArrayBufferView:你可以以二进制帧的形式发送任何 JavaScript 类数组对象
- 异常
INVALID_STATE_ERR
:连接未处于open状态
SYNTAX_ERR
:数据是一个包含未配对代理的字符串
未配对代理 (unpaired surrogates) 指的是在字符串中存在不匹配的 Unicode 代理项。Unicode 中的代理项用于表示一些特殊字符,而代理项对通常是成对出现的,例如表示表情符号的代理对。如果一个字符串中的代理项没有配对,就会出现未配对代理的情况。
事件
响应事件可以用WebSocket中的属性或者使用js监听器
close
WebSocket.onclose
属性返回一个事件监听器,当连接变为CLOSED
的时候会被调用
1 2 3
| WebSocket.onclose = function(event) { console.log(event) }
|
event中包含了时间戳、url、关闭的code等消息
error
当websocket的连接由于一些错误事件的发生 (例如无法发送一些数据) 而被关闭时,一个error事件将被引发。
1 2 3 4 5
| const socket = new WebSocket("ws://localhost:8080"); socket.addEventListener("error", function(event) { console.log(event) }) socket.onerror = ...
|
message
接收新消息时触发
1 2 3 4 5 6
| socket.onmessage = function(event) { console.log(event) } socket.addEventListener("message",function(event) { console.log(event) })
|
event中包含了接收的消息data
open
建立连接时触发
1 2 3
| socket.onopen = function(event) { console.log(event) }
|