携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
websocket介绍
websocket是基于TCP的全双工通信协议,允许服务端主动向客户端推送数据,浏览器和服务器只需要完成一次握手,两者就可以直接创建持久性的链接,并进行双向数据传输。
websocket比较常见的应用场景
- 多人游戏,可以实时发送游戏数据。
- 股票交易平台。
- 直播平台。
- 定位同步。
- 在线聊天室。
- 前端常用的开发时热更新,也是基于websocket实现的。
使用node+weboscket实现简单版本的在线聊天室
- 创建node服务并安装包(nodemon会监控代码变更时,自动重启服务器的插件)
npm i ws uuid
npm i nodemon -D
-
package的script 中添加
"start": "nodemon index.js"便于调试 -
我们先创建websocket实例
const Websocket = require("ws");
const uuid = require("uuid"); //引入创建唯一id模块
- 启动服务器
const ws = new Websocket.Server({ port: 3000 }, () => {
console.log("socket 服务器启动");
});
- 这一步这里我们需要先建立一个数组,因为我们的聊天室会有多个用户,每进来一个用户,就向我们的客户端列表存储一个客户端对象,在此之前需要通过
ws.on监听客户端的连接。 - 监听到客户端进来后,我们只要掌握2个关键的方法即可,发送消息
client.send,client.on("message",() => ())监听消息, 此处的client就是我们每个连接的客户端。
// 客户端列表
const clients = [];
let clientIndex = 1;
// 建立连接
ws.on("connection", (client) => {
// 存储客户端对象
const id = uuid.v4();
console.log(`client ${id} connected`);
let nickname = `用户${clientIndex++}`;
clients.push({
id,
ws: client,
nickname,
});
// 每次当一个客户端连接后,我们可以广播一个消息
sendSocketMessage();
/*监听消息*/
client.on("message", (message) => {
message = JSON.parse(message);
// 昵称修改
if (message.indexOf("/nick") === 0) {
const nicknameArray = message.split(" ")
if (nicknameArray.length >= 2) {
const nicknameMessage = `${nickname} 修改昵称为 ${nicknameArray[1]}`;
nickname = nicknameArray[1];
broadcastSend("nickUpdate", nicknameMessage, nickname);
}
} else {
// 消息发送
broadcastSend("message", message, nickname);
}
});
/*监听断开连接*/
client.on("close", function () {
closeSocket();
});
/**
* 关闭服务,从客户端监听列表删除
*/
function closeSocket() {
for (let i = 0; i < clients.length; i++) {
if (clients[i].id == id) {
// 发送消息
broadcastSend("notification", "退出了", nickname);
clients.splice(i, 1);
}
}
}
/**
* 开启服务,发送消息
*/
function sendSocketMessage() {
for (let i = 0; i < clients.length; i++) {
if (clients[i].id == id) {
// 发送消息
broadcastSend("notification", "来了", nickname);
}
}
}
});
- 发送消息使用频率很高,我们把发送消息单独封装一下
/**
* 广播所有客户端消息
* @param {String} type 广播方式(notification, message)
* @param {String} message 消息
* @param {String} nickname 用户昵称,广播方式为admin时可以不存在
*/
function broadcastSend(type, message, nickname) {
// 遍历所有的客户端,如果连接中
clients.forEach((v) => {
if (v.ws.readyState === v.ws.OPEN) {
v.ws.send(
JSON.stringify({
type: type,
nickname: nickname,
message: message,
})
);
}
});
}
- 然后我们开始处理html部分,用户通过html访问
<!DOCTYPE html>
<html>
<head>
<title>websocket在线聊天室</title>
</head>
<body>
<h3>websocket在线聊天室</h3>
<div>
nick: <input id="user" placeholder="请输入昵称" />
<button onclick="nickUpdateClick()">修改昵称</button>
</div>
<div style="display: flex; margin-top: 10px">
<textarea
id="sendText"
style="margin-right: 6px"
placeholder="请输入消息"
></textarea>
<button onclick="sendMessageClick()">发送消息</button>
</div>
<div>
<ul id="ul"></ul>
</div>
- 把
script直接放入html中就可以了,这里主要是三个步骤,创建实例、监听消息、发送消息。 - 当我们访问页面时,会创建一个实例,一方面当服务器发送数据后,我们可以通过
ws.onmessage接受到数据,另外一方面当我们想修改名称、发送消息的话直接通过ws.send进行发送即可。
<script>
const ws = new WebSocket("ws://localhost:3000/"); // 监听地址端口号
// 建立连接后
ws.onopen = function () {
console.log("服务器连接");
};
// 服务器发送数据后
ws.onmessage = ({ data }) => {
const resData = JSON.parse(data);
console.log("服务端发过来数据", resData);
appendLog(resData.type, resData.nickname, resData.message);
};
// 服务器关闭后
ws.onclose = () => {
console.log("服务器关闭");
appendLog("close");
};
// 昵称修改
function nickUpdateClick() {
if (ws.readyState === WebSocket.OPEN) {
ws.send(
JSON.stringify("/nick " + document.getElementById("user").value)
);
}
}
// 发送消息
function sendMessageClick() {
const msg = document.getElementById("sendText");
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify(msg.value));
}
msg.value = "";
msg.focus();
}
// 进行消息的显示,这里很简单没什么说的
function appendLog(type, nickname = "", message) {
const lessTime = new Date();
const date = `${lessTime.getFullYear()}-${
lessTime.getMonth() + 1
}-${lessTime.getDate()} ${lessTime.getHours()}:${lessTime.getMinutes()}:${lessTime.getSeconds()}`;
const messages = document.getElementById("ul");
const messageElem = document.createElement("li");
let messageText;
if (type === "notification") {
// 来了或者退出了
messageText = `<p style="color: green"> ${nickname} ${message}</p>`;
} else if (type === "nickUpdate") {
// 修改名称
messageText = `<p style="color: orange"> ${message}</p>`;
} else if (type === "message") {
// 消息发送
messageText = `<p style="color: blue"> ${nickname}说: ${message}</p>`;
} else if (type === "close") {
// 服务器关闭
messageText = `<p style="color: red"> 服务器关闭</p>`;
}
messageElem.innerHTML = `${date}<br/>${messageText}`;
messages.appendChild(messageElem);
}
</script>
结语
日常中几乎天天都使用到了websocket,经常听说过这个东西但是没有实践过的小伙伴可以试起来了,是不是比想象的简单多了呢~