WebSocket是一种基于
http
的通信协议,服务端可以主动推送信息给客户端,客户端也可以向服务端发送请求,WebSocket
允许服务端与客户端进行全双工通信。
特点
- 基于
tcp
协议之上,服务端实现比较容易 - 默认端口是
80(ws)
或者443(wss)
,握手阶段采用的http
协议 - 数据格式比较轻量,性能开销小,通信高效
- 可以发送文本或者二进制数据
- 没有同源限制,客户端可以向任意服务器发送信息
- 协议标识符是
ws
,如果加密,那么是wss
实现客户端与服务端通信
新建一个html
文件客户端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>websocket</title>
</head>
<body>
<h3>hello websocket</h3>
<input type="number" id="textContent" />
<button id="handleSend">发送</button>
<button id="auto-send">开启服务端向客户端发消息模式</button>
<hr />
<div id="app"></div>
</body>
</html>
在html
中引入下面一段js
// index.js
const sendDom = document.getElementById('send');
const appDom = document.getElementById('app');
const autoDom = document.getElementById('auto-send');
const inputContent = document.getElementById('textContent');
const socketPath = 'ws://192.168.31.40:3000';
let timer = null;
let num = 0;
const result = [];
// 建立连接
const ws = new WebSocket(socketPath);
const sendMyNum = (isSetInterval = false, to = 'client', val) => {
const setNum = () => {
num = val || Math.ceil(Math.random() * 10);
ws.send(
JSON.stringify({
clientText: `client:hello,我是 ${num}号`,
num,
to
})
);
};
if (isSetInterval) {
timer = setInterval(() => {
setNum();
}, 1000);
} else {
setNum();
}
};
const renderHtml = (data) => {
const { serverText, clientText } = JSON.parse(data);
appDom.innerHTML = '';
result.push({
serverText,
clientText
});
console.log(result);
if (result.length > 0) {
let str = '';
result.forEach((v) => {
str = `<ul>
<li>${v.clientText}</li>
<li>${v.serverText}</li>
</ul>`;
});
appDom.innerHTML = str;
}
};
// 发送数据
ws.onopen = function () {
console.log('websocket connection start');
sendMyNum(false);
};
// 接收服务端发送的消息
ws.onmessage = function (evt) {
console.log(`receive:${evt.data}`);
if (evt.data) {
renderHtml(evt.data);
// 接收数据后关闭定时器
clearInterval(timer);
// sendMyNum(true)
}
};
// 关闭连接
ws.onclose = function () {
console.log('关闭了');
};
// 手动向客户端发送消息
handleSend.onclick = function () {
const val = inputContent.value;
if (val === '') {
alert('请输入你的编号');
return;
}
sendMyNum(false, 'client', val);
};
// 自动开启向客户端发送消息
autoDom.onclick = function () {
sendMyNum(true, 'server');
};
新建一个server
目录,创建服务端代码,主要依赖`nodejs-websocket`[1]这个库是服务端websocket
代码。
var ws = require("nodejs-websocket");
var http = require('http');
const fs = require('fs');
const path = require('path');
const PORT = 8080;
var server = http.createServer(function (request, response) {
response.statusCode = 200;
response.setHeader('Content-Type', 'text/html');
fs.readFile(path.resolve(__dirname, '../', 'index.html'), (err, data) => {
if (err !== null) {
response.end('404');
return;
}
response.end(data);
})
});
server.listen(PORT, function (evt) {
console.log((new Date()) ' Server is listening on port 8080');
});
// websocket
const tcp = ws.createServer(function (connection) {
console.log("New connection")
connection.on("text", function (data) {
const { clientText, num, to } = JSON.parse(data);
if (to === 'server') {
connection.sendText(JSON.stringify({
serverText: `server:${num}号,恭喜你,你太幸运了,你已经被清华录取了`,
clientText: `${num}号`
}));
} else {
if (num > 6) {
connection.sendText(JSON.stringify({
clientText,
serverText: `server:${num}号,你非常优秀, ${num}号,你已经成功被录取了北京大学`,
}))
} else {
connection.sendText(JSON.stringify({
serverText: `server: ${num}号,非常遗憾,${num}号,你落榜了,再接再厉`,
clientText,
}));
};
}
});
connection.sendText(JSON.stringify({
serverText: `server:hello,我们已经建立连接了`,
clientText: `client:你好`
}))
connection.on("close", function (code, reason) {
console.log("Connection closed");
console.log(code, reason);
});
}).listen(3000);
tcp.on('error', (err) => {
console.log(err);
})
我们可以执行命令node server.js
,打开浏览器http://localhost:8080/
打开network
,ws
下面可以看到有客户端向服务端发送的消息,也有服务端向客户端发送的两条信息。
我们看到请求头的一些信息
我们可以看到请求头里
General
代码语言:javascript复制Request URL: ws://192.168.31.40:3000/
Request Method: GET
Status Code: 101 Switching Protocols
Request Headers
代码语言:javascript复制Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cache-Control: no-cache
Connection: Upgrade
Host: 192.168.31.40:3000
Origin: http://localhost:8080
Pragma: no-cache
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: Mk8Au85XqQTn vuDsfr/kw==
Sec-WebSocket-Version: 13
Upgrade: websocket
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36
当输入数字,向服务端发送消息时,服务端会返回对应信息。通常来讲,服务端会不定时的向客户端推送信息,客户端拿到推送信息进行一系列的页面状态展示等。
通过以上的例子,我们基础的了解到websocket
的使用
总结
WebSocket
其实需要客户端对WebSocket
处理主要是这三个步骤
- 建立连接、断开连接
- 发送数据,接收数据
- 处理错误
- 本文 示例代码[2]
更多WebSocket
可以参考`websocket`[3]
参考资料
[1]nodejs-websocket
: https://www.npmjs.com/package/nodejs-websocket
[2]示例代码: https://github.com/maicFir/lessonNote/tree/master/node/websocket
[3]websocket
: https://www.wangdoc.com/webapi/websocket.html