node.js - socket.io 不向房间内的其他人发送事件
问题描述
所以我试图弄清楚一个非常基本的socket.io应用程序发生了什么。我通过让 2 个不同的选项卡注册为不同的用户并尝试查看另一个选项卡是否获得事件来对此进行测试。前端都没有接收到其他事件,但服务器确实可以正确接收到事件。我的前端是 vue.js,我认为我的代理设置正确。我不确定为什么连接到同一个房间的房间 2 人不会收到基于文档的事件。
编辑:如果我删除 roomId 的 .to ,则消息将仅复制给发送消息的用户:/不确定这是否意味着什么。
Edit2:这与 rabbitmq 适配器不能用于中继消息有关。通过删除该中间件,一切正常。
Node.js 服务器
import http from 'http';
import express from 'express';
import { Server } from 'socket.io';
const adapter = require('socket.io-amqp');
const app = express();
const server = http.createServer(app);
const io = new Server(server,{
path: '/socket'
});
io.adapter(adapter('amqp://localhost'));
app.get('/',(req,res) => {
res.send('<h1>Hello World, Again</h1>')
});
io.on('connection',(socket) => {
const query = socket.handshake.query;
const userId = query['userId'] as string;
const roomId = query['roomId'] as string;
if(!userId || !roomId)
{
console.log('failed to connect - userId or roomId is undefined');
socket.disconnect();
return;
}
socket.join(roomId);
console.log(`connection - user: ${userId}, room: ${roomId}`);
socket.on('newValue',(e) => {
socket.to(roomId).emit('newValue',{
userId: userId,
value: e.value
});
console.log(`roomId: ${roomId}, userId: ${userId}, value: ${e.value}`);
});
socket.on('disconnect',(reason)=> {
socket.to(roomId).emit('userDisconnect',{
userId: userId
});
console.log(`disconnect - user: ${userId}, room: ${roomId}`);
});
socket.to(roomId).emit('newUser',{
userId
});
});
const PORT = 3000;
server.listen(PORT,() => {
console.log(`listening on http://localhost:${PORT}`);
});
管理套接字的 Vue.js 视图
<template>
<div class="room">
<div class="p-grid">
<div class="p-col-12">
<playing-card :value="selectedValue" class="center-card"/>
</div>
</div>
<div class="p-grid">
<div class="p-col-12">
<value-selector @change="onValueChange"/>
</div>
</div>
</div>
</template>
<script lang="ts">
import 'vue-router';
import { userStore } from '../store/index';
import { io, Socket } from 'socket.io-client';
import { Options, Vue } from 'vue-class-component';
import ValueSelector from '../components/ValueSelector.vue';
import PlayingCard from '../components/PlayingCard.vue';
@Options({
components: {
PlayingCard, ValueSelector
}
})
export default class Room extends Vue {
selectedValue = -1;
private socket!: Socket | null;
private closeSocket(): void {
if(this.socket)
{
this.socket.close();
this.socket = null;
}
}
private configureSocket(): void {
if(!this.socket)
{
this.socket = io({
path: '/socket',
reconnection: true,
reconnectionDelayMax: 10000,
query: {
roomId: this.$route.params.roomId as string,
userId: userStore.getters.userId as string
}
});
this.socket.on('newValue',(e)=>{
console.log(e);
});
this.socket.onAny((eventName,e)=>{
console.log(eventName);
console.log(e);
});
}
}
mounted(): void {
this.configureSocket();
}
onValueChange(values: any) {
this.selectedValue = values.newVal;
if(this.socket)
{
this.socket.emit('newValue', {
value: this.selectedValue
});
}
}
unmounted(): void {
this.closeSocket();
}
}
</script>
<style lang="scss" scoped>
.center-card {
margin: auto;
}
</style>
Vue.config.js
module.exports = {
devServer: {
proxy: {
'/socket': {
target: 'http://localhost:3000',
changeOrigin: true,
ws: true,
}
}
}
}
服务器日志
[nodemon] 2.0.7
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: ts,json
[nodemon] starting `ts-node src/index.ts`
listening on http://localhost:3000
connection - user: ls91m4il, room: 123, socketId: 86zN3g6maJu1z0OzAAAB
connection - user: pq68znqa, room: 123, socketId: xvKKzXhEbCrnz_l_AAAD
roomId: 123, userId: ls91m4il, socketId, 86zN3g6maJu1z0OzAAAB value: 5
roomId: 123, userId: pq68znqa, socketId, xvKKzXhEbCrnz_l_AAAD value: 13
对于 onAny 的事件响应或具有匹配命名事件的订阅,不会触发前端日志。
解决方案
首先,socket.to(roomId).emit(...)
将向 roomId 中的每个套接字发送消息,除了socket
. 如果要发送到 中的所有套接字roomId
,则可以使用io.to(roomId).emit(...)
. 我不清楚你是想发送到所有套接字还是除了发起者之外的所有套接字,所以我想确保你理解这方面的事情。
可以通过调试和日志记录来确保自己可以解决问题的事情:
确保两个客户端都连接到您的服务器并保持连接。记录和事件的实际
socket.id
情况将为您提供很好的了解。connect
disconnect
确保两个客户端都请求相同的
roomId
. 如果roomId
每个的不同,那么只有一个套接字,roomId
并且socket.to().emit()
没有其他人可以发送到。确保发送
newValue
消息的客户端没有发布导致页面重新加载的表单,因此旧套接字断开连接并创建新套接字。登录点 #1 应该确保您没有看到这种情况发生。我提到这一点主要是因为这是一个常见的错误,尽管我没有看到足够多的实际 HTML 页面来知道这对你来说是否是个问题。记录服务器上的每条传入消息。不仅记录消息,还记录消息的
socket.id
来源。这将允许您重建整个消息流。
如果没有所有这些数据,我们就无法确定问题所在。这种类型的问题需要收集数据,然后跟踪线索,直到您可以更准确地看到正在发生的事情和没有发生的事情。如果我不得不冒险猜测,我想知道您是否对#1 或#2 有问题。
推荐阅读
- android - 如何解决工具:替换 Xamarin.forms 应用程序中的错误
- node.js - 使用 Twilio Voice 连接到受密码保护的 Zoom 呼叫
- jsf - JSF 1.2 在新选项卡中打开外部链接。不分散电流
- excel - 如何声明全局变量,将它们设置为模块中的工作簿并稍后使用?
- javascript - VueJS - Vuex 突变和 Vue-Router 重定向的正确顺序?
- postgresql - Qt 时间戳从 Epoch(1970) 到 2000 年开始的 Postgresql 时间戳。如何添加偏移量并将毫秒转换为微秒?
- python - 形成一个斐波那契三角形,使得每个数字都是左对角线或右对角线上方两个数字的总和
- rust - rust clone() vs Rc 还是 Arc?
- angular - 我想要选择框,用户可以在其中输入他的数据
- google-sheets - 如何将查询的结果拆分为两列