1.websocket的由来和使用场景
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
也就是说当需要保持长连接(实时通讯)和大量消耗带宽的场景时,websocket就有了用武之地。
2.聊天室的例子
websocket有很多的使用场景,我会在后面依次写出例子,今天的例子就是聊天室功能(消息传输、长连接即时通讯)
服务端代码
:
const UUID = require('uuid');
const WebSocket = require("ws");
const WebSocketServer = WebSocket.Server;
const wss = new WebSocketServer({ port: 8080 });
console.log("listening port 8080");
//广播处理函数
wss.broadcast = function (request = {}) {
wss.clients.forEach((client) => {
client.send(JSON.stringify(request));
});
}
wss.on("connection", (ws) => {
ws.uuid = UUID.v1();
//广播上线消息
wss.broadcast({id:ws.uuid,message:"上线",state:"online"});
ws.on("message", (message) => {
console.log('received :%s', message);
//广播群消息
wss.broadcast({id:ws.uuid,"message": message,state:"speaking"});
});
//广播退出消息
ws.on("close", () => {
wss.broadcast({id:ws.uuid,message:"退出",state:"cancel"});
})
});
前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<style>
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.textArea {
width: 600px;
resize: none;
}
.footer {
display: flex;
flex-direction: row;
justify-content: flex-end;
/* align-items: center; */
width: 600px;
height: 100px;
background: #dea1a1;
border: solid 1px #000;
}
.input {
/* align-self: */
flex-grow: 1;
resize: none;
}
.show{
width: 600px;
height: 400px;
background: #dea1a1;
overflow:auto;
}
.message_container{
margin: 10px;
}
.message_name{
background: rgb(126, 146, 199);
color: aliceblue;
display: inline-block;
padding: 3px;
border-radius: 5px;
}
.message_content{
background: rgb(197, 255, 238);
color: rgb(56, 57, 58);
display: inline-block;
padding: 2px;
border-radius: 5px;
margin-left: 10px;
margin-top: 10px;
border: solid 5px #eee;
}
.speak{
color:aquamarine;
}
.online_speak{
display: inline-block;
padding: 2px;
border-radius: 5px;
margin-left: 10px;
margin-top: 10px;
color: #eee;
}
</style>
</head>
<body>
<div class="container">
<div id="textarea" class="show" contenteditable="true"></div>
<!-- <textarea id="textarea" class="textArea" rows="20"></textarea> -->
<div class="footer">
<textarea id="input" class="input"></textarea>
<button onclick="sendMessage()">WEBSOCKET提交</button>
</div>
</div>
</body>
<script>
//说话者字框颜色
let speak_colors = new Map();
let $textarea = $("#textarea");
let $input = $("#input");
let onOpen = function () {
// console.log("Socket opened.");
// socket.send("Hi, Server!");
}
let onClose = function () {
console.log("Socket closed.");
}
let onMessage = function (response) {
let { state, message, id } = JSON.parse(response.data);
let content = "";
if (state === "online") {
speak_colors.set(id,{prefix:Math.random});
content = `<div class="message_container"><div class="message_name">${id}</div><div class="online_speak">${message}</div></div>`;
}
else if (state === "cancel") {
content = `<div class="message_container"><div class="message_name">${id}</div><div class="online_speak">${message}</div></div>`;
}
else {
content =`<div class="message_container"><div class="message_name">${id} <span class="speak">发言</span></div><br/><div class="message_content">${message}</div></div>`;
}
$textarea.html(`${$textarea.html()}${content} <br/><br/>` );
}
let onError = function () {
console.log("We got an error.");
}
socket = new WebSocket("ws://127.0.0.1:8080/");
socket.onopen = onOpen;
socket.onclose = onClose;
socket.onerror = onError;
socket.onmessage = onMessage;
function sendMessage() {
socket.send($input.val()||"");
}
</script>
</html>
3.结语
websocket的使用是非常简单的,需要注意的是下面这个情况:
可以看出来网络监听中只有一条消息,始终websocket只会占用一个通道,减少了tcp信道的数量和服务器频繁切换的情况减少了负载。要知道开启和关闭连接是个非常耗资源的操作。