1、websocket简介
传统http协议,是基于请求和响应的,无法直接做到客户端向客户端发送消息。 websocket协议是基于tcp的一种新的网络协议。实现了浏览器与服务器全双工通信。全双工:客户端可以主动给服务器发送消息,服务器也可以主动给客户端发送消息。 websocket是一种持久协议,http是非持久的 传统http协议实现即使聊天,必须通过ajax轮询,就是客户端会一直向服务器发送请求来确认是否有消息,浪费性能和资源。
2、使用websocket
2.1、websocket的基本使用
客户端:index.html
<!DOCTYPE html><html><head><meta charset="utf-8" /><title>WebSocket测试</title></head><body style="text-align: center"><h2>WebSocket测试</h2><div><input type="text" id="txt" /><button onclick="sendWebSocket()">发送</button><br /><button onclick="checkWebSocket()">测试WebSocket</button><button onclick="connectWebSocket()">连接WebSocket</button><button onclick="closeWebSocket()">关闭WebSocket</button><br /><hr /><div id="message"></div></div></body><script type="text/javascript">let websocket = null;// 检查是不是支持websocketfunction checkWebSocket() {if ("WebSocket" in window) {setMessageInnerHTML("您的浏览器支持 WebSocket!");} else {setMessageInnerHTML("您的浏览器不支持 WebSocket!");}}// 打印信息function setMessageInnerHTML(innerHTML) {document.getElementById("message").innerHTML += innerHTML + "<br/>";}// 连接WebSocketfunction connectWebSocket() {//1、打开一个websocketwebsocket = new WebSocket("ws://localhost:3000/");websocket.onopen = function () {setMessageInnerHTML("websocket 已连接...");};websocket.onmessage = function (evt) {var received_msg = evt.data;setMessageInnerHTML("收到消息:" + received_msg);};websocket.onclose = function () {setMessageInnerHTML("WebSocket 已关闭...");};}// 向服务端发消息function sendWebSocket() {if (websocket) {if (websocket.readyState == websocket.OPEN) {var message = document.getElementById("txt").value;websocket.send(message);} else {setMessageInnerHTML("WebSocket 未连接...");}} else {setMessageInnerHTML("WebSocket 未创建...");}}// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function () {closeWebSocket();};// 关闭WebSocket连接function closeWebSocket() {websocket.close();}</script></html>
服务端 Node
app.js
const ws = require("nodejs-websocket");const PORT = 3000;//创建server,每次只要有用户连接,回调执行就会给用户创建一个connect对象const server = ws.createServer((connect) => {console.log("用户连接成功");//用户传来数据,触发text事件connect.on("text", (data) => {console.log(`接受到用户的数据:${data}`);//接受到数据后给用户响应数据connect.sendText(data);});//连接关闭触发close事件connect.on("close", () => {console.log("连接断开");});//注册error事件,用户端口后就会触发该异常connect.on("error", () => {console.log("用户连接异常");});});server.listen(PORT, () => {console.log("监听3000");});
2.2、实现简单的聊天功能
通过打开几个窗口,验证不同用户的加入离开
index.html
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><title>Title</title><style>/*div {width: 200px;height: 200px;border: 1px solid #000;}*/</style></head><body><input type="text" placeholder="请输入" /><button>发送</button><!-- 显示内容 --><div></div><!-- websocket在浏览器的使用 H5提供了websocket的API--><script>let input = document.querySelector("input");let button = document.querySelector("button");let div = document.querySelector("div");//创建WebSocket('WebSocket服务器地址')let socket = new WebSocket("ws://localhost:3000/");//监听WebSocket事件 open和WebSocket服务器连接成功触发socket.addEventListener("open", () => {div.innerHTML = "连接成功";});//给webSocket发送消息button.addEventListener("click", () => {let value = input.value;socket.send(value);input.value = "";});const TYPE_ENTER = 0;const TYPE_LEAVE = 1;const TYPE_MSG = 2;//接受websocket服务的消息socket.addEventListener("message", (e) => {let data = JSON.parse(e.data);//把消息显示到div,以追加的方式let dv = document.createElement("div");//为不同的消息类型添加效果dv.innerHTML = data.msg + "---" + data.time;if (data.type === TYPE_ENTER) {dv.style.color = "green";} else if (data.type === TYPE_LEAVE) {dv.style.color = "red";} else {dv.style.color = "blue";}div.appendChild(dv);});//端口服务socket.addEventListener("close", () => {console.log("服务断开");});</script></body></html>
app.js
const ws = require('nodejs-websocket');//进入消息const TYPE_ENTER = 0;//离开消息const TYPE_LEAVE = 1;//正常消息const TYPE_MSG = 2;//记录当前连接的用户数量let count = 0;const server = ws.createServer(conn => {console.log('新连接');count++;//给用户一个固定的名字conn.userName = `用户${count}`;//告诉所有用户,有人加入聊天室broadcast({type: TYPE_ENTER,msg: `${conn.userName}加入聊天室`,time: new Date().toLocaleDateString()});//接受到客户端的数据触发该事件conn.on('text', data => {//接受到某个用户的数据,告诉所有的用户此消息,广播broadcast({type: TYPE_MSG,msg: data,time: new Date().toLocaleDateString()});});//关闭连接conn.on('close', () => {console.log('关闭连接')count--;//有人退出也告诉所有的用户broadcast({type: TYPE_LEAVE,msg: `${conn.userName}离开了聊天室`,time: new Date().toLocaleDateString()})});//发送异常conn.on('error', () => {console.log('异常');});});//广播const broadcast = (msg) => {//server.connection表示所有的用户server.connections.forEach(item => {//遍历出每个用户,挨个发消息item.send(JSON.stringify(msg));});}server.listen(3000, () => {console.log('监听3000');});
