使用Socket.io库制作一个简单的实时聊天室
WebSocket介绍
传统的http,在客户端没发送请求给服务器之前是不会有响应的,客户端发送请求后服务器才作出响应,明显是单向的,如果要持续获取资源就得不断重复请求
后来就有了长轮询(Long polling)的方法,客户端让HTTP请求保持一段时间,即使没有数据的时候也得保持连接。再后来,就有了WebSocket
WebSocket是专门设计来做实时应用的协议,WebSocket和HTTP很像,WebSocket请求的URL用的是ws或者wss,在HTTP协议里对应HTTP和HTPPS
客户端如果要发起WebSocket请求,需要在请求首部里作出说明,Connection的值写成Upgrade,Upgrade的值写成WebSocket,服务器收到请求后会看到连接要求升级,升级成什么在Upgrade里找,于是服务器就知道客户端要建立WebSocket连接,建立连接后就可以传输数据了
WebSocket建立连接
我们用node.js来生成服务器,首先npm init -y
初始化,然后安装Websocket依赖npm i ws
,创建一个server.js
作为服务器文件
在service里引入安装的模块,生成一个WebSocket实例并指名使用的端口
const WebSocket=require('ws')
const wss=new WebSocket.Server({port:3000})
加入事件操作,有人连接进来的时候使用connection
来指明这个状态,并用wx参数表示不同的单一连接,有人退出的话要在单一连接中进行,也就是使用wx参数指明close
状态的时候
wss.on('connection',ws=>{
console.log('有人连接进来');
ws.on('close',()=>{
console.log('有人退出了');
})
})
测试一下,但是现在直接用浏览器访问服务器是没有效果的,因为浏览器是使用HTTP访问的,不会告诉服务器用WebSocket连接,所以还需要创建一个index.html文件,在html文件里面成一个WebSocket实例,参数里填写URL,因为是在开发所以直接使用ws,实例应用中一般是wss,是安全版的ws
const ws=new WebSocket('ws://localhost:3000')
ws.addEventListener('open',()=>{//ws实例事件监听函数
console.log('连接上服务器了');
ws.send('12345,')
})
node server.js运行服务器,然后运行index.html,打开页面前端和后端的控制台都有提示了,关闭页面也会有提示,也就是断开连接,WebSocket的连接功能也就实现了
不过还缺少了数据传输功能,还是在单一连接里进行操作,如果收到message就把客户端的信息处理一下返回给客户端。客户端也需要设置在连接上就马上发送信息给服务器并监听message事件,有数据就在控制台输出返回的数据
//服务器
ws.on('message',data=>{//接收到数据就把数据加工一下返回给客户端
ws.send(data+'今晚打老虎')
})
//客户端
ws.addEventListener('open',()=>{
console.log('连接上服务器了');
ws.send('12345,')//连上服务器就发送数据给服务器
})
ws.addEventListener('message',({data})=>{//接收服务器返回的数据
console.log(data);
})
刷新页面,可以看到控制台打印的消息无误就代表实现了数据传输
Socket.io库
Socket.io库也有用到WebSocket协议,但是对不支持WebSocket的浏览器会回退到HTTP轮询,还提供自动重连,是一个更高级的库,有了WebSocket的基础就可以使用Socket.io实现一个简单的实时聊天应用
还是和上面操作大致一样,初始化,npm i express socket.io
安装express和socket.io依赖,创建server.js和index.html
先用安装好的express库生成一个实例app再调用http模块,并使用app实例生成一个服务器实例,也就是基于http模块生成服务器实例,写起来更方便一些
const app=require('express')()//生成app实例
const server=require('http').createServer(app)//生成服务器实例
当接收到请求的时候,把html文件作为响应的文件
app.get('/',(req,res)=>{
res.sendFile(__dirname+'/index.html')//__dirname绝对路径
})
html代码,主要有input输入框和按钮,聊天内容就放在ul标签里
注意服务器不能直接用app.listen,不然还是使用HTTP进行交互,使用刚刚创建的server实例创建一个socket.io实例,使用service实例监听端口
const server=require('http').createServer(app)//生成服务器实例
const {Server}=require('socket.io')//导入模块
const io=new Server(server)创建io实例
server.listen('3000',()=>'服务器开启')//监听3000端口
和之前WebSocket连接操作很类似,有人连接进来的时候使用connection
来指明这个状态并用socket参数表示不同的单一连接,有人退出的话要在单一连接中进行,也就是使用socket参数指明disconnect
状态的时候
io.on('connection',socket=>{
console.log('有人进入聊天室');
socket.on('disconnect',()=>{
console.log('有人离开聊天室');
})
})
客户端也要作出相应的连接,和刚刚WebSocket不同的是,因为这是服务器响应文件,可以直接在script标签里指定路径,这样可以调用到io函数
///socket.io/socket.io.js服务器响应文件,自动生成
<script src="/socket.io/socket.io.js"></script>
<script>
const socket=io()
</script>
运行服务器,在浏览器里访问localhost:3000,可以看到服务器控制台有提示,代表连接成功了,关掉浏览器页面服务器也有提示,代表断开连接了
连接成功就可以来实现实时消息的功能了,服务端在socket连接的时候开启chat message
事件,客户端先获取form和input两个元素,并且监听form的有提交动作的时候,先取消防止默认刷新事件,输入框有内容的时候触发chat message事件传入输入框的内容,然后清空一下输入框
//服务端
socket.on('chat message',msg=>{
console.log(msg);
})
//客户端
const form=document.querySelector('form')
const input=document.querySelector('input')
form.addEventListener('submit',e=>{
e.preventDefault()//取消事件默认动作
if(input.value){
socket.emit('chat message' , input.value)//触发chat message事件并传入输入框里的值
input.value=''
}
})
重启一下服务器,在浏览器里访问localhost:3000,在输入框里输入值点击发送按钮触发chat message
事件将值传给服务器
服务器收到后还得广播给所有人,这样才能更新聊天室的内容,在chat message
事件下用io这个实例触发一下chat message,并且把从客户端收到的数据发送出去
socket.on('chat message',msg=>{
io.emit('chat message',msg)
})
客户端获取一下ul元素,使用socket实例监听chat message
事件,服务器发来数据就生成新的li元素,把数据内容放进li元素里面,然后使用appendChild为ul新增子元素li
socket.on('chat message',msg=>{
const li =document.createElement('li')//创建新元素
li.textContent=msg
ul.appendChild(li)//新增子元素
})
服务器重启之后打开多个页面输入消息,其他页面也会有同步的消息,也就实现了实时聊天室了
转载自:https://juejin.cn/post/7158251550253514760