一.整体思路
聊天室最重要的就是要聊天,那聊天最重要的就是要收到消息,还有就是要确保消息可以准确的传达到你想传达到的人的聊天界面中。有了前面条件,我们就要先考虑怎么找到对方,然后是怎么确保对方可以收到消息,然后才是却确保对方收到消息的准确性和即时性。
二.拆分模块
既然涉及到了聊天的分发,就要考虑到服务器的存在了,因为本身前端是不可以进行这种消息的分发和接收的,所以我们引入了node.js中的exress轻量级框架来充当中间件,进行消息的转发和接收。中间件解决了,那我们就要解决即时通信的问题了,当然,这个问题可以采用轮询和长轮询的方法以及webssocket方法来实现,当我们有了具体的实现方法和理论时,我们就好像是可以放大招的奥特曼,秒杀一切小怪兽!!!!!!!
为什么是websocket?
不要你觉得,我要我觉的,就是要用websocket,不服去打三丰啊。哈哈哈,言归正传。websocket是H5新出的一种支持双向通信的网络协议,该协议是基于TCP传输协议,并且复用了HTTP的握手通道。如果想要建立websocket连接,客户端需要通过HTTP请求与WebSocket服务器端协商升级协议。协议升级完成后,后续的数据交换就会遵守webSocket的协议了。说了这么多,还是没说为什么是它,但请客官别走,好戏还在后头呢。在webSocket协议没出之前,为了实现消息的推送技术,所用到的技术都是AJAX轮询,简单的讲就是在特定的时间间隔内,有浏览器发出HTTP请求,然后服务器返回最新的数据给客户端。这种方法有一种很明显的缺点,就是要不断的向服务器发送请请求,然而真正有效的数据只可能是其中很小的一部分,浪费了很多的带宽等资源,就像妈妈在整个冬天都会让我们穿秋裤,但我们只有在真的受不了的时候才会把它穿上,浪费了妈妈的很多唾沫,但收益却是很小的。所以在实现聊天这个功能的时候,我们选择的是webSocket。
三.具体实现
之前的提到过要用node.js中express(不知道的同学,请自行百度),那我们就用它搭一个简单的服务器,话不多说,上代码
服务器端的代码实现
//在服务器端安装的依赖是socket.io,是封装好的webSokcet的库,express依赖
const app = require('express')
//引入express
const server = require("http").Server(app)
const io = require("socket.io")(server)
let clients = []//
let friends = []//在线好友列表
//在socket.io中,on表示接受消息,emit表示发送消息
io.on("connection", socket => {//设置connection关键词,表示客户端是否连接成功
console.log('有客户端连接')//如果有客户端上线,在控制台上打印提醒
console.log(socket.id)//打印每个socket中的socket.id,这是每个socket连接的唯一标识
clients.push(socket.id)
socket.on("msg",function(data){//设置msg关键词,接受客户端发送的消息
console.log(data)
switch(data.type){
case 'online':{
socket.broadcast.emit('ON_LINE',{time:data.time,text:'用户'+data.name+'加入群聊'})
//broadcast是广播,广播给所有在线的socket用户,提示当前用户上线提醒
const list = friends
list.push({user:data.name,uncode:data.uncode})
把用户名和唯一的socket.id以数组的形式储存起来
//把所有的在线用户发送给所有在线的客户端
io.sockets.emit('broadcast',{list})
//发送在线的好友列表
console.log(data)
}
break;
case 'content':{
console.log(data.type)
socket.broadcast.emit('CONTENT',{user:socket.name,text:data.content})
//给客户端发送消息
// io.sockets.connected[data.socketid].emit('P2P',{text:data.content})
}
break;
case 'P2P':{
//以唯一的socket.id为标识,点对点的发送信息
io.sockets.connected[data.socketid].emit('P2P',{text:data.content})
}
break;
}
});
socket.on('disconnect',() => {//设置关键词disconnect,监听客户端下线通知
console.log('客户端下线',socket.id)
//找到当前用户信息的索引
let index = friends.findIndex(v => v===socket.name)
friends.splice(index,1)
//在数组中删除用户信息
io.sockets.emit('broadcast',{friends})
//更新新的在线列表
socket.broadcast.emit('CLOSE',{time:new Date().toLocaleString(),text:'用户'+socket.name+'离开了群聊'})
//使用broadCast广播用户离开的消息
})
});
server.listen(8001);
客户端代码实现
import React,{ Component } from 'react'
import socket from 'socket.io-client'
//在客户端使用到的依赖是socket.io-client,它和socket.io成对配合使用
//一般socket的接收会在componentDidMount()生命周期函数中
componentDidMount(){
const name = window.prompt('请输入昵称');
//上线提醒
socket.emit('msg',{type:'online',name:name,uncode:socket.id,time:new Date().toLocaleString()})
//接收好友列表
socket.on('broadcast',(data) => {
console.log(data)
const todolist = JSON.parse(JSON.stringify(this.state.friend))
console.log(todolist)
todolist.push({user:name,uncode:socket.id})
console.log(todolist)
this.setState({
friend:{user:name,uncode:socket.id}
})
})
//接受好友上线提醒
socket.on('ON_LINE',(data)=>{
console.log(data)
window.alert(data.time + data.text )
})
//接受服务器端发送来的消息(广播)
socket.on('CONTENT',(data) =>{
const list = []
list.push({user:data.user,text:data.text})
//把消息记录保存下来
this.setState({
saveValue: list
})
})
//点对点发送的信息
socket.on('P2P',(data)=>{
const list = []
console.log(this)
list.push({user:data.user,text:data.text})
//把消息记录保存下来
this.setState({
saveValue: list
})
console.log(data.text)
})
}
//在发送按钮上绑定send函数
send = () => {
const inputValue = this.state.sendValue
socket.emit('msg',{type:'content',content:inputValue}); //发送消息
this.setState({sendValue: null})
const list = this.state.saveValue
list.push({user:this.state.username,text:inputValue})//记录聊天记录
this.setState({
sendValue:list
})
}
再加上一些简单的页面设置,就可以得到一个完整的聊天页面
@三丰,叫你勒!