uniapp如何实现Websocked单聊,群聊
那什么是websocket?
对于第1次听说WebSocket技术的人来说,两者有什么区别?
websocket 是全双工相互通信的,可以实现两边即时通讯,尔传统的通讯方式客户端按照某个时间间隔不断地向服务端发送请求,请求服务端的最新数据然后更新客户端显示。这种方式实际上浪费了大量流量并且对服务端造成了很大压力,不断的发数据请求,也给前端带来压力。
uniapp如何实现websocket 到项目中运行呢?
这里我已一个自写小型的uniapp聊天app为例子 (uniapp其实有自定义的websock api)
1)在websocke.js 中建立websocket与后台的连接在mian.js 中引入 确保用户全局注册
import Vue from 'vue'
const socket = new WebSocket("ws://10.16.51.78:8001")
// 将socket 挂载到vue原型中全局使用
Vue.prototype.socket = socket
// main中注册用户
socket.onopen = function(e) {
socket.send(
JSON.stringify({
name: "张三",
msg: '我是张三',
})
);
};
socket.onclose = function(e) {
console.log("服务器关闭");
};
socket.onerror = function() {
console.log("连接出错");
};
socket.onmessage = function(e) {
// 处理所有的websocket发送来的数据
let message = JSON.parse(e.data)
console.log(message)
};
在main.js中引入websocket
// ipv4 地址
Vue.prototype.serverUrl = 'http://10.16.51.78:3000'
require("./websocket.js")
2)在页面中使用websocket
// 举个栗子 如果现在是在index.vue 页面中 需要发送一天数据到后端websock 并保存到数据库
methods:{
sendMsg(){
// 发送socket
this.socket.send(
JSON.stringify({
name: "王五",
msg: "你好,我是王五",
})
);
},
loginWebsocket() {
// 建立连接
if (window.WebSocket) {
this.socket.onclose = function(e) {
console.log("服务器关闭");
};
this.socket.onerror = function() {
console.log("连接出错");
};
// 接收服务器的消息
this.socket.onmessage = function(e) {
let message = JSON.parse(e.data)
console.log(message) // 打印后台返回的数据{name: "王五",msg: "你好,我是王五",}
};
}
},
}
3)服务器端处理(node为栗子)
// main.js 引入node-websocket
const ws = require("nodejs-websocket") // 启动socket
require("./websocket")(ws)
// websocket.js
module.exports = function (ws) {
// websocket 处理
var server = ws
.createServer(function (conn) {
console.log("开始建立连接")
// 向客户端发送信息
conn.on("text", function (obj) {
conn.sendText(JSON.stringify(obj))
})
conn.on("close", function (code, reason) {
console.log("关闭连接")
})
conn.on("error", function (code, reason) {
console.log("异常关闭")
})
console.log("WebSocket建立完毕")
})
.listen(8001)
// WebSocket处理结束
}
如何把websock传输的数据保存呢?
websock内部并没有给一个定一个特殊的函数来保存数据,需要我们自己去写,保存前台发送的数据和给后台返回数据并不是同时进行的,先后顺序都取决于程序员,举一个栗子。
module.exports = function (ws) {
// websocket 处理
var server = ws
.createServer(function (conn) {
console.log("开始建立连接")
conn.on("text", function (obj) {
// 向客户端发送信息
conn.sendText(JSON.stringify(obj))
// 保存数据 mongodb为例
let saveDaet = {
userId: obj.bridge[0],
friendId: obj.bridge[1],
message: obj.msg,
types: "0",
time: new Date(),
state: 1,
}
let message = new Message(saveDaet)
message.save(function (err, result) {
if (err) {
console.log(err)
}
})
})
conn.on("close", function (code, reason) {
console.log("关闭连接")
})
conn.on("error", function (code, reason) {
console.log("异常关闭")
})
console.log("WebSocket建立完毕")
})
.listen(8001)
// WebSocket处理结束
}
单聊和群聊在代码是的区别,如何实现?
在建立全局的websock连接时,后台生成了连接成员并且注册,在已经是好友的情况况下,可以给用户发送短信,
在线接收,不在线websock就会报错,这是应为好友断开了websock连接,群聊则不同,需要独立给群创建一个websock连接,如果不在线,报错,上代码---》
// 仅供参考
const moment = require("moment") // 时间处理
var dbserver = require("../dao/dbserver") // 保存数据的js文件
module.exports = function (ws) {
// websocket 处理
let users = [] // 创建连接用户的数组
var conns = {}
let groups = [] // 创建连接群的数组
function boardcast(obj) {
// 单聊
if (obj.bridge && obj.bridge.length) {
dbserver.websocketSendOneMsg(obj) // 保存消息
// 好友不在线不能发
obj.bridge.forEach((item) => {
if (conns[item]) {
conns[item].sendText(JSON.stringify(obj))
} else {
return
}
})
return
}
// 群
if (obj.groupId) {
dbserver.websocketSendGroupMsg(obj) // 保存消息
console.log(groups)
let group = groups.filter((item) => {
return item.id === obj.groupId
})[0]
group.users.forEach((item) => {
// 好友不在线不能发
console.log(item)
if (conns[item.uid]) {
conns[item.uid].sendText(JSON.stringify(obj))
} else {
return
}
})
return
}
// 广播
server.connections.forEach((conn, index) => {
conn.sendText(JSON.stringify(obj))
})
}
var server = ws
.createServer(function (conn) {
console.log("开始建立连接")
conn.on("text", function (obj) {
obj = JSON.parse(obj)
conns[obj.uid] = conn
switch (obj.type) {
// 创建连接 广播上线的用户
case 1:
let isuser = users.some((item) => {
return item.uid === obj.uid
})
if (!isuser) {
users.push({
nickname: obj.nickname,
uid: obj.uid,
status: 1,
})
} else {
users.map((item, index) => {
if (item.uid === obj.uid) {
item.status = 1
}
return item
})
}
boardcast({
type: 1,
date: moment().format("YYYY-MM-DD HH:mm:ss"),
msg: obj.nickname + "加入聊天室",
users: users,
groups: groups,
uid: obj.uid,
nickname: obj.nickname,
bridge: obj.bridge,
})
break
// 注销 下线的用户广播
case 2:
users.map((item, index) => {
if (item.uid === obj.uid) {
item.status = 0
}
return item
})
boardcast({
type: 1,
date: moment().format("YYYY-MM-DD HH:mm:ss"),
msg: obj.nickname + "退出了聊天室",
users: users,
groups: groups,
uid: obj.uid,
nickname: obj.nickname,
bridge: [],
})
break
// 创建群
case 10:
// 排查是否重复注册群 标记
// 给用户加入的群和创建的群注册,如果创建了就加入,没创建就创建。不区分群主
let isrevew = false
for (let i = 0; i < groups.length; i++) {
if (obj.groupId == groups[i].id) {
isrevew = true
}
}
if (isrevew == true) {
// 聊天室纯在
let group = groups.filter((item) => {
return item.id === obj.groupId
})[0]
let inGroup = group.users.filter((item) => {
return item.uid === obj.uid
})[0]
if (inGroup) {
// 在群里
boardcast({
type: 1,
date: moment().format(
"YYYY-MM-DD HH:mm:ss"
),
msg: "你已经是群成员了",
users: users,
groups: groups,
uid: obj.uid,
nickname: obj.nickname,
bridge: obj.bridge,
})
} else {
group.users.push({
uid: obj.uid,
nickname: obj.nickname,
})
boardcast({
type: 1,
date: moment().format(
"YYYY-MM-DD HH:mm:ss"
),
msg:
obj.nickname +
"加入了群" +
obj.groupName,
users: users,
groups: groups,
uid: obj.uid,
nickname: obj.nickname,
bridge: obj.bridge,
})
}
isrevew == false
} else {
// 聊天室不纯在
groups.push({
id: obj.groupId,
name: obj.groupName,
users: [
{
uid: obj.uid,
nickname: obj.nickname,
},
],
})
boardcast({
type: 1,
date: moment().format("YYYY-MM-DD HH:mm:ss"),
msg: obj.nickname + "创建了群" + obj.groupName,
users: users,
groups: groups,
uid: obj.uid,
nickname: obj.nickname,
bridge: obj.bridge,
})
isrevew == false
}
break
// 加入群
case 20:
let group = groups.filter((item) => {
return item.id === obj.groupId
})[0]
group.users.push({
uid: obj.uid,
nickname: obj.nickname,
})
boardcast({
type: 1,
date: moment().format("YYYY-MM-DD HH:mm:ss"),
msg: obj.nickname + "加入了群" + obj.groupName,
users: users,
groups: groups,
uid: obj.uid,
nickname: obj.nickname,
bridge: obj.bridge,
})
break
// 发送消息
default: // 保存信息
boardcast({
type: 2,
date: new Date(),
msg: obj.msg,
uid: obj.uid,
nickname: obj.nickname,
bridge: obj.bridge,
groupId: obj.groupId,
status: 1,
})
break
}
})
conn.on("close", function (code, reason) {
console.log("关闭连接")
})
conn.on("error", function (code, reason) {
console.log("异常关闭")
})
console.log("WebSocket建立完毕")
})
.listen(8001)
// WebSocket处理结束
}
总结
无论是群聊还是单聊,其实质是相同的,建立连接,发送数据,保存数据,返回数据,单人聊天是给指定的用户发送信息,群聊,类似于广播,
需要源码的朋友可以评论区联系我,也希望大家提出更好的见解和意见。