当前位置: 首页 > 科技观察

WebSocket简介:简易聊天室

时间:2023-03-15 01:38:02 科技观察

大家好,我是前端西瓜哥。今天我们使用WebSocket实现一个简单的聊天室。WebSocket是一个应用层协议,有点类似于HTTP。但与HTTP不同的是,它支持真正的全双工,即不仅客户端可以主动向服务器发送消息,服务器也可以主动向客户端发送消息。尤其是后者,让我们不再基于HTTP长轮询或短轮询这种低效的方式来实现服务端通知。与HTTP相比,WebSocket的服务端推送更轻量,可以减轻服务端的压力。服务器端nodejs没有提供原生的WebSocket模块。如果要实现,需要基于net模块,按照WebSocket标准实现。因为实现起来很复杂,所以我选择直接使用第三个库ws。yarnaddws类似于nodejs的原生http模块。ws库支持WebSocket服务器或客户端,并提供低级API。我们先实现服务端代码:import{WebSocketServer}from"ws";//创建一个ws服务constwsSever=newWebSocketServer({port:6060,});//每当客户端建立一个ws连接,它就会创建一个wsobjectwsSever.on("connection",(ws)=>{//当有新客户端连接时,广播wsSever.clients.forEach((client)=>{client.send(`有人进入聊天室,当前聊天室人数:${wsSever.clients.size}`);});//广播任何客户端发送的消息ws.on("message",(data)=>{constmsg=data.toString();wsSever.clients.forEach((client)=>{client.send(msg);});});//广播ws.on("close",()=>{wsSever.clients.forEach((client)=>{client.send(`有人退出聊天室,当前聊天室数量:${wsSever.clients.size}`);});});});每当一个client客户端建立websocket连接,就会触发wsServer的connection事件,然后得到一个ws对象。这个ws对象代表了某个客户端和服务器之间的连接。我们可以用它来接收对应客户端的消息,让服务端主动推送消息给指定的客户端。新创建的ws对象在建立连接时保存到wsServer.clients集合,在连接关闭时删除。所以我们可以使用这个wsServer.clients来广播,实现聊天室功能。客户端客户端使用本机WebSocket对象与服务器建立WebSocket连接。constws=newWebSocket('ws://localhost:6060');ws.addEventListener('message',(event)=>{constdiv=document.createElement('div');div.innerText=event.data;document.body.append(div);})//点击发送按钮将输入框中的内容发送到服务器。价值);input.value='';}效果简单的聊天室改为使用Socket.IOws库,是底层实现,比较简单。另一个库Socket.IO的底层使用了ws,并增强了它的功能以提供更多的能力。与ws相比,Socket.IO可以做到:如果浏览器不支持WebSocket,会回退到HTTP长轮询方案来模拟WebSocket(WebSocket在2011年完成了RFC,已经很久了,目前主流已经支持WebSocket的浏览器没了,不支持WebSocket的浏览器都是渣)。使用心跳包机制实现自动重连。包缓存。断开连接时发送数据将保存数据并在重新连接后发送。自定义事件支持。播送。使用流行的wheel可能比尝试自己一个一个地实现更好的选择。让我们用Socket.IO来实现前面的功能。Server:import{Server}from"socket.io";//socket.iov3.x默认不允许跨域,需要在配置中显式设置允许跨域constio=newServer(6060,{cors:{原点:“*”}});io.on("connection",(socket)=>{//当有新客户端连接时,广播io.emit("chat",`有人进入聊天室,当前聊天室人数:${io.engine.clientsCount}`);//广播任何客户端发送的消息socket.on("chat",(data)=>{io.emit("chat",data);});//当客户端退出时,broadcastsocket.on("disconnect",()=>{io.emit("chat",`有人退出聊天室,当前聊天室数量:${io.engine.clientsCount}`);});});需要特别注意的是,从v3.x版本的Socket.IO开始,默认是不允许跨域的,需要在配置中显式设置为允许跨域。客户端:constsocket=io('ws://localhost:6060');socket.on('chat',(data)=>{constdiv=document.createElement('div');div.innerText=data;document.body.append(div);})//点击发送按钮将输入框中的内容发送到服务器constinput=document.querySelector('input');constbtn=document.querySelector('button');btn.onclick=()=>{console.log('发送');socket.emit('聊天',input.value);input.value='';}Socket.IO的优势在于满足了生产环境底层的非业务能力,让我们可以心无旁骛的编写业务代码。缺点是失去了灵活性。由于定制化,需要使用Socket.IO的客户端库和服务端库的封装,这在某种意义上背离了网络协议标准。当有跨语言场景时(比如前端是JS,后端是Java),需要提供对应语言的Socket.IO实现。demomo已经放在github上,使用方法在README.md中有说明。https://github.com/F-star/websocket-chat-demo完本文演示了WebSocket的简单聊天室功能是如何实现的,希望对您有所帮助。