??砥礪前行,不負余光,永遠在路上??
前言
因為業(yè)務需要我這里是小程序 結合 nodejs來實現(xiàn)的websocket通信
一、服務端
1、主要是通過node+express+websocket搭建
2、代碼大概結構
3、nodejs 啟動入口文件 引入自己的websocket文件,這里是為了和 http 服務結合起來,將server傳入
自己的文件中,http.createServer(app)
客戶端那邊就可以通過以下網(wǎng)址去訪問了
ws://${IP}:3000/ // 3000也就是自己node啟動的端口 另外 + 本機ip
const { port } = require('../config/index')
var app = require('../app');
var debug = require('debug')('projectname:server');
var http = require('http');
app.set('port', port);
var server = http.createServer(app);
try {
const Websocket = require('../utils/websocket')(server)
} catch (error) {
console.log(error);
}
4、websocket.js 工具文件完整代碼
做個說明,這個是包含了我自己的部分業(yè)務需要,如果自己用不上數(shù)據(jù)庫相關的東西可以刪除,
我是在 headres 拿到token自己去去解析用戶信息,還在headers 中攜帶了一個用戶信息,
區(qū)分空間主要是在 連接websocket 的url上處理的,相同的房間請求同一個url,代碼中也包含了詳細注釋。
/*
* @Date: 2023-05-24 09:23:47
* @LastEditTime: 2023-05-26 13:51:52
*/
const jwt = require('../utils/jwt')
const { literal, Op, Sequelize } = require("sequelize");
const { User, Room, RoomUser, Record, Standings } = require('../models/index')
const { uuid } = require('../utils/index');
const WebSocket = require('ws');
module.exports = function (server) {
try {
// 創(chuàng)建WebSocket服務器
const wss = new WebSocket.Server({ server });
// 管理連接和空間的數(shù)據(jù)結構
const connections = new Map(); // 存儲連接的Map,key為空間名稱,value為連接數(shù)組
// 監(jiān)聽連接事件
wss.on('connection', async function connection (ws, req) {
addToSpace(ws, req.url.split('/')[1]);
console.log('New client connected', '------------------------------>');
// 在這里可以訪問 WebSocket 請求的請求頭
let { id } = jwt.verifyToken(req.headers.token);
const roomId = req.headers['room-id']
//通過 id去獲取用戶信息 / 不然可能用戶更新了信息但是還是原來的token
const res = await User.findOne({
where: { id },
raw: true,
});
//查看用戶是否加入到房間
let userIsJoin = await Record.findOne({
where: { roomId, fromId: id, type: '2' },
raw: true,
});
if (!userIsJoin) { //沒有就加一個
await Record.create({ id: uuid(), roomId, fromId: id, type: '2', createTime: Sequelize.fn('NOW') })
}
//有新的連接 也要下發(fā)信息
console.log(`${res.nickName}加入了房間`, roomId);
const data = { spaceName: req.url.split('/')[1], userJoin: `${res.nickName}加入了房間` }
handleIncomingMessage(ws, JSON.stringify(data));
// 監(jiān)聽消息接收事件
ws.on('message', function incoming (message) {
console.log('Received message:', message.toString('utf8'), '----------->', message);
handleIncomingMessage(ws, message.toString('utf8'));
});
// 監(jiān)聽連接關閉事件
ws.on('close', async function close () {
console.log('Client disconnected');
//查看用戶是否加入到房間
let userIsJoin = await Record.findOne({
where: { roomId, fromId: id, type: '3' },
raw: true,
});
if (!userIsJoin) { //沒有就加一個
await Record.create({ id: uuid(), roomId, fromId: id, type: '3', createTime: Sequelize.fn('NOW') })
}
const data = { spaceName: req.url.split('/')[1], userLeave: `${res.nickName}退出了房間` }
handleIncomingMessage(ws, JSON.stringify(data));
removeConnectionFromAllSpaces(ws);
});
});
// 處理接收到的消息
function handleIncomingMessage (ws, message) {
const messageString = JSON.parse(message);
// 假設消息格式為 "SPACE_NAME|MESSAGE_CONTENT"
const { spaceName } = messageString
// connection.send(content);
const connectionsInSpace = connections.get(spaceName);
if (connectionsInSpace) {
// 向當前空間的所有連接發(fā)送消息
connectionsInSpace.forEach(connection => {
// if (connection == ws && connection.readyState === WebSocket.OPEN) {
// console.log('send----------------------------');
connection.send(JSON.stringify(messageString));
// }
});
}
}
// 將連接添加到指定空間
function addToSpace (ws, spaceName) {
console.log(spaceName, '房間名稱');
let connectionsInSpace = connections.get(spaceName);
if (!connectionsInSpace) {
connectionsInSpace = new Set();
connections.set(spaceName, connectionsInSpace);
}
connectionsInSpace.add(ws);
}
// 將連接從所有空間中移除
function removeConnectionFromAllSpaces (ws) {
connections.forEach(connectionsInSpace => {
connectionsInSpace.delete(ws);
});
}
} catch (error) {
console.log(error);
}
}
二、客戶端部分
1、小程序在oonload中 連接websocket
onLoad(options) {
console.log(options);
const { roomNum, roomId } = options
if (roomNum) {
this.setData({ roomNum })
}
// this.getRoomInfo(wx.getStorageSync('roomId')) 這是拉取房間信息的接口 相當yu是在收到服務端消息之后自己去獲取最新的信息
this.connectWebSocket() // 連接WebSocket服務器
},
2、this.connectWebSocket 代碼和向服務器發(fā)送消息的代碼如下
下面的WS_URL
有標注。roomNum 就是房間編號是需要客戶端這邊確定 。
// WS_URL = ws://${IP}:3000/
文章來源:http://www.zghlxwxcb.cn/news/detail-469699.html
/**
* 連接WebSocket服務器
*/
connectWebSocket: function () {
var _this = this
wx.connectSocket({
url: WS_URL + wx.getStorageSync('roomNum'),
header: {
"token": wx.getStorageSync('token'),
"room-id": wx.getStorageSync('roomId'),
},
success: (res) => {
console.log('WebSocket連接成功:', res)
// wechatSIPlayAudio('WebSocket連接成功')
// _this.getRoomInfo(wx.getStorageSync('roomId'))
},
fail: function (res) {
console.log('WebSocket連接失敗:', res)
}
})
wx.onSocketOpen(function (res) {
console.log('WebSocket連接已打開')
_this.setData({ socketOpen: true })
})
wx.onSocketError(function (res) {
console.log('WebSocket連接打開失敗:', res)
})
wx.onSocketClose(function (res) {
console.log('WebSocket連接已關閉:', res)
_this.setData({
socketOpen: false
})
})
wx.onSocketMessage(function (res) {
// 收到服務器發(fā)送的數(shù)據(jù)之后 重新拉取 更新列表
const data = JSON.parse(res.data)
console.log('接收到服務器發(fā)送的數(shù)據(jù):', data)
if (data.toId === wx.getStorageSync('userId')) {
getApp().util.toast(data.toMsg)
wechatSIPlayAudio(data.toMsg)
setTimeout(() => {
_this.getRoomInfo(wx.getStorageSync('roomId'))
}, 3000);
} else {
_this.getRoomInfo(wx.getStorageSync('roomId'))
}
//用戶加入 播報
if (data.userJoin) {
wechatSIPlayAudio(data.userJoin)
}
//用戶退出 播報
if (data.userLeave) {
wechatSIPlayAudio(data.userLeave)
}
})
},
/**
* 發(fā)送WebSocket消息
*/
sendSocketMessage: function (params) {
if (this.data.socketOpen) {
wx.sendSocketMessage({
data: JSON.stringify({
spaceName: wx.getStorageSync('roomNum'),
...params
})
})
}
},
3、客戶端說明
小程序這邊邏輯 主要是在 收到服務端發(fā)送的消息之后去拉取最新的數(shù)據(jù),來更新界面。文章來源地址http://www.zghlxwxcb.cn/news/detail-469699.html
到了這里,關于nodejs 中使用websocket 并且區(qū)分空間,實現(xiàn)收到客服端消息 同步給房間內(nèi)所有連接,小程序中使用websocket,區(qū)分房間、空間的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!