当前位置:网站首页>浅谈WebSocket
浅谈WebSocket
2022-07-28 12:49:00 【Maic】
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
Request URL: ws://192.168.31.40:3000/
Request Method: GET
Status Code: 101 Switching Protocols
Request Headers
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
边栏推荐
- Better and more modern terminal tools than xshell!
- R语言使用lm函数构建多元回归模型(Multiple Linear Regression)、并根据模型系数写出回归方程、使用confint函数给出回归系数的95%置信区间
- 记一次使用pdfbox解析pdf,获取pdf的关键数据的工具使用
- Holes in [apue] files
- 数据库系统原理与应用教程(061)—— MySQL 练习题:操作题 21-31(五)
- My friend sent me some interview questions
- SAP UI5 FileUploader 控件实现本地文件上传,接收服务器端的响应时遇到跨域访问错误的试读版
- 数据库系统原理与应用教程(062)—— MySQL 练习题:操作题 32-38(六)
- R语言ggplot2可视化:使用ggpubr包的ggviolin函数可视化小提琴图、设置palette参数自定义不同水平小提琴图的边框颜色
- The strongest distributed locking tool: redisson
猜你喜欢

DDoS protection with iptables

Humiliation, resistance, reversal, 30 years, China should win Microsoft once

word打字时后面的字会消失是什么原因?如何解决?

30天刷题训练(一)

30 day question brushing plan (IV)

Jar package

少儿编程 电子学会图形化编程等级考试Scratch二级真题解析(判断题)2022年6月

酷炫操作预热!代码实现小星球特效

【安全】 阅读 RFC6749 及理解 Oauth2.0 下的授权码模式

接口调不通,如何去排查?没想到10年测试老鸟栽在这道面试题上
随机推荐
Uva1599 ideal path problem solution
7. Dependency injection
图的遍历(BFS&&DFS基础)
长封闭期私募产品再现 业内人士看法各异
在 Kubernetes 中部署应用交付服务(第 1 部分)
POJ1860货币兑换题解
Denial of service DDoS Attacks
R语言因子数据的表格和列联表(交叉表)生成:使用summay函数分析列表查看卡方检验结果判断两个因子变量是否独立(使用卡方检验验证独立性)
DXF读写:标注样式组码中文说明
《如何打一场数据挖掘赛事》入门版
Rolling update strategy of deployment.
Tutorial on the principle and application of database system (059) -- MySQL exercise questions: operation questions 1-10 (III)
DOJP1520星门跳跃题解
What is the reason why the words behind word disappear when typing? How to solve it?
我秃了!唯一索引、普通索引我该选谁?
Deployment之滚动更新策略。
R语言ggplot2可视化:可视化散点图并为散点图中的数据点添加文本标签、使用ggrepel包的geom_text_repel函数避免数据点标签互相重叠(自定义指定字体类型font family)
I miss the year of "losing" Li Ziqi
数据库系统原理与应用教程(061)—— MySQL 练习题:操作题 21-31(五)
数据库系统原理与应用教程(059)—— MySQL 练习题:操作题 1-10(三)