思考:这种网页版的聊天功能应该如何去实现??
websocket介绍
WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。
websocket是一种持久协议,http是非持久协议
现在很多网站都有实时推送的需求,比如聊天,客服咨询等
早期没有websocket时,通过ajax轮询,由于http请求,服务器无法给浏览器主动发送数据,因此需要浏览器定时的给服务器发送请求(比如1s一次),服务器把最新的数据响应给浏览器。这种模式的缺点就是浪费性能和资源。
websocket是一种网络协议,允许客户端和服务端全双工的进行网络通讯,服务器可以给客户端发消息,客户端也可以给服务器发消息。
websocket基本使用
在HTML5中,浏览器已经实现了websocket的API,直接使用即可。
WebSocket-MDN
创建websocket对象
1 2 3 4 var Socket = new WebSocket(url, [protocol] );
websocket事件
事件
事件处理程序
描述
open
Socket.onopen
连接建立时触发
message
Socket.onmessage
客户端接收服务端数据时触发
error
Socket.onerror
通信发生错误时触发
close
Socket.onclose
连接关闭时触发
websocket方法
方法
描述
Socket.send()
使用连接发送数据
Socket.close()
关闭连接
使用nodejs开发websocket服务
我们刚刚使用了官网提供的echo服务,接下来我们自己通过nodejs实现一个简单的websocket服务。
使用nodejs开发websocket需要依赖一个第三方包。Nodejs Websocket
项目搭建
新建一个websocket server端的项目
1 2 3 4 5 mkdir server-demo cd server-demoyarn init -y yarn add nodejs-websocket touch app.js
开发服务程序
在app.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 const ws = require ('nodejs-websocket' )const PORT = 3000 const server = ws.createServer(connect => { console .log('新的连接' ) connect.on('text' , str => { console .log('接收:' + str) connect.sendText(str.toUpperCase() + '!!!!' ) }) connect.on('close' , () => { console .log('连接关闭了' ) }) connect.on('error' , err => { console .log('连接异常' ) }) }) server.listen(PORT, function ( ) { console .log(`websocket server listening on ${PORT} ` ) })
启动服务
在终端中看到websocket server listening on 3000
就说明webserver服务启动成功了
进行测试
修改客户端中index.js
文件中的连接地址,重新进行测试
1 2 3 const URL = 'ws://localhost:3000' const websocket = new WebSocket(URL)
websocket开发聊天室程序
app.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 const ws = require ('nodejs-websocket' )const PORT = 3000 const TYPE_MSG = 0 const TYPE_ENTER = 1 const TYPE_LEAVE = 2 let userCount = 0 const server = ws.createServer(connect => { console .log('有新用户连接了' ) userCount++ connect.userName = 'user' + userCount broadcast({ type: TYPE_ENTER, msg: connect.userName + '进入了聊天室' , date: new Date ().toLocaleTimeString() }) connect.on('text' , msg => { broadcast({ type: TYPE_MSG, msg: msg, date: new Date ().toLocaleTimeString() }) }) connect.on('close' , () => { console .log('用户断开连接' ) userCount-- broadcast({ type: TYPE_LEAVE, msg: `${connect.userName} 离开了聊天室` , date: new Date ().toLocaleTimeString() }) }) connect.on('error' , () => { console .log('连接失败' ) }) }) function broadcast (msg ) { server.connections.forEach(conn => { conn.sendText(JSON .stringify(msg)) }) } server.listen(PORT, () => { console .log('服务器启动成功了' , PORT) })
index.html
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 <!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 > <style > /* div { width : 200px ; height : 200px ; border : 1px solid #000 ; } */ </style > </head > <body > <input type ="text" placeholder ="请输入需要发送的内容" /> <button > websocket测试</button > <div class ="show" > </div > <script > var input = document .querySelector('input' ) var button = document .querySelector('button' ) var div = document .querySelector('div' ) var socket = new WebSocket('ws://localhost:3000' ) socket.addEventListener('open' , function ( ) { div.innerText = '恭喜你,与服务端建立连接了' }) button.addEventListener('click' , function ( ) { socket.send(input.value) input.value = '' }) socket.addEventListener('message' , function (e ) { var data = JSON .parse(e.data) var dv = document .createElement('div' ) dv.innerHTML = data.msg + '----' + data.date if (data.type === 0) { dv.style.color = 'green' } if (data.type === 1) { dv.style.color = 'red' } if (data.type === 2) { dv.style.color = 'gray' } div.appendChild(dv) }) socket.addEventListener('close' , () => { div.innerHTML = '与服务器断开连接' }) </script > </body > </html >
如果使用原生的websocket进行开发,会比较麻烦,比如支持的事件太少,发送的数据只能是字符串格式的,提供的api也很少,类似于广播这种方法都没有,需要自己封装。
socket.io基本使用
socketio
基于socket.io开发完整的聊天室
Tips:
Please indicate the source and original author when reprinting or quoting this article.