前言
本篇主要致力于开发一个简单的聊天室项目(纯手打),现在进行开源(未部署),主要记录一些代码注释,未来有兴趣会继续优化
介绍websocket服务
开发聊天室,我们需要用到WebSocket这个网络通信协议,那么为什么会用到它呢?初次接触 WebSocket 的人,都会问同样的问题:我们已经有了 HTTP 协议,为什么还需要另一个协议?它能带来什么好处?答案很简单,因为 HTTP 协议有一个缺陷:通信只能由客户端发起。举例来说,我们想了解今天的天气,只能是客户端向服务器发出请求,服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。我们只能使用”轮询”:每隔一段时候,就发出一个询问,了解服务器有没有新的信息。最典型的场景就是聊天室。轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。因此,工程师们一直在思考,有没有更好的方法。WebSocket 就是这样发明的。
前端代码(含注释)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| <!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>Document</title> <style> /* div{ width: 200px; height: 200px; border: 1px solid #000; } */ </style> </head> <body> <!--输入内容--> <input type="text" placeholder="输入内容">
<!-- 发送请求--> <button>发送消息</button> <!--显示结果--> <div></div>
<script> var input = document.querySelector('input') var button = document.querySelector('button') var div = document.querySelector('div') const TYPE_ENTER = 0 const TYPE_LEAVE = 1 const TYPE_MSG = 2
// 演示websocket // h5提供了websocket的API
// 1.创建websocket // 参数1: websocket的服务地址 var socket = new WebSocket('ws://localhost:3000')
// 2.open:当 websocket连接成功的时候会触发 socket.addEventListener('open',function() { div.innerHTML = '连接服务成功' })
// 3.主动給websocket服务发送消息 button.addEventListener('click',function() { var value = input.value socket.send(value) input.value = '' })
// 4.接收websocket服务数据 socket.addEventListener('message',function(e) { //console.log(e.data) div.innerHTML = e.data会把消息覆盖掉 var data = JSON.parse(e.data) var dv = document.createElement('div') dv.innerText = 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 = 'pink' } div.appendChild(dv) })
socket.addEventListener('close',function() { div.innerHTML = '服务断开连接' }) </script>
</body> </html>
|
js代码(含注释)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| // 1.导入nodejs-websocket包 const { time } = require('console') const ws = require('nodejs-websocket') const TYPE_ENTER = 0 const TYPE_LEAVE = 1 const TYPE_MSG = 2
/*
消息不应该是简单的字符串,消息应该是一个对象 type 消息的类型:0:用户进入聊天室的消息 1:用户离开聊天室的消息 2:正常的聊天消息 msg 消息的内容 time 聊天的时间
*/
// 2.记录连接的用户数量 let count = 0
const PORT = 3000 // 3.创建server // 3.1 处理用户请求 // 3.2 每次只要有用户连接,函数就会被执行,会给当前连接的用户创建一个connect对象 const server = ws.createServer(connect => { console.log('有用户连接') count++ // 4.给用户起名 connect.userName = `用户${count}` // 5.告诉所有用户有人加入聊天室 //broadcast(`${connect.userName}进入聊天室`) broadcast({ type: TYPE_ENTER, msg: `${connect.userName}进入聊天室`, time: new Date().toLocaleTimeString() })
// 6.每当接收到用户传递的数据,这个text事件就会触发 connect.on('text', data => {
// 6.1 接收用户信息的时候,告诉所有用户发送的消息 //broadcast(data) broadcast({ type: TYPE_MSG, msg : data, time: new Date().toLocaleTimeString() }) console.log('接收到了用户的数据', data)
// 7.给用户一个响应的数据 connect.send(data) })
// 8.只要websocket连接断开, close事件就会触发 // 9.关闭连接的时候触发 connect.on('close', () => { console.log('连接断开') count--
// 10.告诉所有用户有人离开聊天室 //broadcast(`${connect.userName}离开聊天室`) broadcast({ type: TYPE_LEAVE, msg : `${connect.userName}离开聊天室`, time: new Date().toLocaleTimeString() }) })
// 注册error,处理用户的错误信息 connect.on('error', data => { console.log('用户连接异常') }) })
// 给所有用户发送消息 function broadcast(msg){ // server.connections表示所有用户 server.connections.forEach(item => { //将对象转换成字符串 item.send(JSON.stringify(msg)) }) }
server.listen(PORT, () => { console.log('服务启动成功,端口监听' + PORT) })
|
启动服务
实机效果