Socket.io: 双重连接

创建于 2011-08-23  ·  42评论  ·  资料来源: socketio/socket.io

客户端以某种方式发生了两次连接(意味着所有处理程序都被调用了两次),无法自行重现这种情况,但是不断收到错误报告,如果在已连接的设备上调用socket.socket.connect(),其行为是完全相同的套接字(在websocket和flashsocket上测试)

Socket.IO client bug

最有用的评论

按照基本示例,我仍然遇到此问题。

编辑:我发现了一个修复程序,尽管我不确定它是否正确。 本质上,它所需要的只是使用

io.once('connection', ...)

代替

io.on('connection', ...)

所有42条评论

作为快速hack,您可以使用“强制新连接”:错误的配置

我还在应用程序中观察到了该错误。
复制是下一个。 在具有websocket连接的FF中,发生了一些错误。 然后又发生了另外3个重新连接事件。 建立这3个新连接后,浏览器收到3条消息,而不是一条。

也许重新连接逻辑中有一些错误? 某种东西,它会产生多个重新连接而不是一个。

我曾在不支持websockets(例如FF 3.6)的较旧浏览器中看到问题,其中在dom ready事件中初始化socket.io(jQuery中的“ $()”)会导致多个连接,而在稍后的window.load中进行初始化事件没有。 我发现这个特定问题始终可以重现。 不确定是否与您看到的东西相同,但症状看起来非常相似。

同样的问题在这里。 问题是,如果服务器由于某种原因而崩溃,然后重新开机,则每次重新连接都会导致n + 1次响应。 因此,如果说3台服务器崩溃,则每台服务器发出4个响应。 刷新页面即可解决此问题。 是否有人为此找到了解决方案[即使是临时的?]

这可能不是永久性的解决方案,但我重新排列了代码,以便每个事件都独立绑定,并且自动重新连接上的复制问题似乎已解决。

me.socket.on('connect', function () {
});

me.socket.on('message', function(data) {

});

me.socket.on('disconnect', function() {

});

通过捕获的Wireshark转储进行了一周的调试后,我设法找到了原因并重现了该错误。

简而言之,重新连接逻辑非常脆弱。 它取决于许多可以并行运行的计时器,并且会导致多次重新连接。 这行https://github.com/LearnBoost/socket.io-client/blob/master/lib/socket.js#L511是此错误的主要原因。

现在完整复制:

  1. 与客户端连接到服务器。
  2. 通过阶乘将慢速代码放入您的服务器(我们应该将node.js mainloop挂起4-8秒):
    函数fibo(n){
    如果(n <2)返回1;
    返回fibo(n-2)+ fibo(n-1);
    }
    将其放入auth-section。 这应该在握手时调用:
    io.set('authorization',function(data,accept){
    console.info(“ Fibo ::” + fibo(41));
    您应该在节点控制台中进行实验,以找到fibo(N),
    将阻塞主循环4-8秒。
  3. 现在,您应该快速重启服务器。
    慢速代码将适用于连接。
    应该通知客户它不是握手状态。
    现在,它尝试重新连接。
    在控制台中,您将看到几个重新连接尝试(如果您将日志记录在“重新连接/重新连接”回调中)。
    减速后,我们将永远重复。

在现实生活中,这是通过服务器响应速度至少降低了几秒钟来重现的。
这可能是在node.js负载过重并且响应有所延迟时发生的。
否则某些网络速度下降也可能导致这种行为。
服务器重新启动后,也可以复制它。

这行(socket.js,511):
self.reconnectionTimer = setTimeout(也许是重新连接,self.reconnectionDelay);

在连接呼叫后安排事件。 如果连接响应延迟至少一秒钟,则会触发该连接并将新的重新连接放入队列。 2秒后,它将添加另一个,以此类推。

我做了一个修复程序,但是它没有经过测试,看上去也不很牢固。 主要问题-如何推断哪个回调/计时器可以同时运行到maybeReconnect函数。
这一行: https :

如果将Socket.io客户端重构为使用某些状态机,则其原因可能更简单。 当前状态分布在不同的标志上(连接,连接,重新连接等)。 在许多功能中,我看到了诸如“ if(!self.reconnecting)”之类的防护功能。
状态机可以简化此逻辑以具有一组状态和事件。 而且计时器只能用于触发事件。 如果此事件的状态不正确,状态机可以忽略此事件,而不会打扰自己。

我还没有找到适合JS的STM,但是来自Ruby的STM可以轻松移植到JS: https :

修复此问题后肯定会+1。 我一直在尝试寻找解决此问题的方法,而没有直接修改socket.io或socket.io-client,但是不幸的是,我可靠地想到的唯一方法就是禁用重新连接。 绝对不是一个好的解决方案,尤其是随着移动设备使用量的增加,重新连接是一个巨大的需求。

有谁知道这如何归入开发人员优先级列表?

啊。 看来此问题已从问题分配给了第3伊甸园: https :

我已经为客户端做了修复,并发送了请求请求。 它在0.8.4中运行良好,并且在其他版本中也可以运行良好。 但是它要求禁用源中使用AJAX(或CORS)进行握手的功能。 参见: https :

很抱歉恢复了这么老的问题。 我使用的是相信最新版本的socket.io(或者至少我做了npm install socket.io)。 对于我来说,这个问题仍然会发生,对于整个socket.io和node.js来说我还是比较陌生。 我还遇到了一些问题,有时第一个连接(在我一次只发生的两个连接中)有读取错误。 如果我正确地说出cris,则表示您的修复已落实,因此不应再发生,但除非我错过了重要因素,否则它仍然会发生。

编辑-

似乎是cri分叉了socket.io并对此进行了修复,但该修复未提交给原始的socket.io?

@JTallis我遇到的问题与@gdiz相同,他的建议效果很好。 如果您的问题相似,建议您尝试一下并让我们知道它的工作原理。

我在0.9.16中也遇到了这个问题,我认为这是最新版本。 gdiz如何避免这种情况的发生? 不太了解。

我的...我花了几个小时来弄清楚我的应用程序有什么问题,以及为什么在连接丢失并续订后服务器和客户端之间的消息重复出现...

使用0.9.16我可以确认这个问题

我可以在同一文件node.js文件中使用以下客户端和服务器代码随意获得双重连接事件:

"use strict";
var server = require('socket.io');
var client = require('socket.io-client');

setTimeout(function () {
    var io = server.listen(8888);

    io.of('/chat').on('connection', function (socket) {
        console.log('Server: /chat connection');
    });

    io.sockets.on('connection', function (socket) {
        console.log('Server: connection');
    });
}, 2000);

var socketAddress = 'http://localhost:8888/chat';
var socket = client.connect(socketAddress);

socket.on('connect', function () {
    console.log("Client: connect");
});

socket.on('error', function () {
    console.log("Client: error");
    socket.socket.reconnect();
});

一些奇怪的事情:

1)如果我通过从网址中删除“ / chat”将命名空间连接更改为普通连接,则只有一个连接事件。

2)如果我立即启动服务器,请将setInterval时间更改为零,则没有初始连接错误,只有一个连接事件。

有任何解决方法或解决方法?

有同样的问题。 如果socket.io服务器意外重新启动,则客户端将重新连接两次,因此每个消息将由客户端处理两次。 确实搞乱了我在客户端的计数。

1.0.0-pre2版本存在相同的问题。 当我休息socket.io时,我有两个“ 400 Bad Request”。

今天将对此进行调查!

今天将对此进行调查!

如果您需要更多详细信息,日志或屏幕,请不要犹豫! 不是每次都这样。

在第2755行的1.0.6的客户端socket.io.js中:

Request.prototype.create =函数(isBinary,supportsBinary){
var xhr = this.xhr = new XMLHttpRequest({agent:this.agent,xdomain:this.xd});
...
}

我相信设置是一个好主意:
xhr.timeout = Manager._timeout的实例-10毫秒
这样,您可以防止在客户端创建多个客户端套接字。
在服务器端,多个套接字将心跳超时。

基本的socket.io“入门”示例(http://socket.io/get-started/chat/)具有此双重套接字连接问题。

以下情况之一(按概率增加)导致来自单个浏览器选项卡连接的双套接字连接:
a)从第一个浏览器选项卡本身连接到localhost:3000后
b)在第二个浏览器选项卡上连接到localhost:3000后
c)在连接到(localhost:3000)之前,保持浏览器控制台处于打开状态

其他观察:

 io.on('connection', function(socket){
    console.log('a user connected: ' + socket.id);
    socket.on('disconnect', function(){
       console.log('a user disconnected');
       console.log(socket.nickname + ' has disconnected from the chat.');
    });
});
  1. 单个浏览器选项卡请求中有两个不同的socket.id
  2. “重复”套接字连接会自行断开连接,大约在console.log中显示“未定义已从聊天断开连接”。
  3. 使用快速生成器4.2(使用Morgan),然后实现“入门”示例,“良好”浏览器连接会生成单行的快速日志,例如“ GET / 304 1ms”。 但是只要有这种“双”套接字连接,就会有两个明确的日志:“ GET / 304 1ms”和“ GET / 200 3ms-386b”

我正在使用Mac,Chrome,Express 4.2和最新的socket.io。

创建两个日志之间存在时间差异。 当Chrome自动将我的“ lo”自动填写为“ localhost:3000 ”时,将触发第一个日志,而当我按Enter键时,将触发第二个日志。

我有一个“ X个用户已连接”控制台日志消息,当我自己的浏览器触发2或3个用户连接通知时,我很烦。

现在,我必须承认我对问题的解决方案是注释掉console.log行。 伙计们,请继续努力。

我仍然在最新版本中看到此问题。 有任何更新吗?

我也看到了1.0的问题

根本无法重现。 有人可以发表完整的例子吗?

于2014年11月14日星期五凌晨2:44:50 Rex Pechler [email protected]
写道:

我也看到了1.0的问题

-
直接回复此电子邮件或在GitHub上查看
https://github.com/Automattic/socket.io/issues/474#issuecomment -62934229

我明天看看是否可以举一个简单的例子。

我可能会复制它。 我正在使用socket.io 1.3.5并表达4.12.4。

我的快速应用程序位于127.0.0.1:3000上,我打开浏览器并键入ip地址和socket.io,仅打开一个websocket。

我有一个域名,例如abc.com,并将其转发到127.0.0.1。 我在浏览器中打开abc.com,在index.html文件中有一行;

<script>
        var socket = io('http://localhost:3000/mysql');

        socket.on('processlist', function (data){
            console.log(data);
        });
</script>

这将打开2个websocket。

我还没有用代理尝试过nginx。 我会尽快通知您。

screen shot 2015-05-29 at 23 53 29

仍然遇到这个问题。 对我来说,它发生在服务器重启时-我在触发服务器的初始连接事件时附加了socket.on('message')事件处理程序,并且如果在客户端打开时重启服务器,则该事件会触发多次(客户端一直在等待服务器重新启动)。

目前,我的解决方法是“消除”套接字事件的附加影响,使其仅在第一个服务器连接上发生,如下所示:

client.socketEventsAttached = false;

socket.on('connect',function(){
     if (!client.socketEventsAttached){
          attachSocketEvents();
     }
});

您也可以按照@gdiz的建议,将消息事件侦听器放在socket.on('connect')侦听器

@bbcollinsworth客户端对象是什么?

仍然用新的socketio和基本示例遇到此问题。

按照基本示例,我仍然遇到此问题。

编辑:我发现了一个修复程序,尽管我不确定它是否正确。 本质上,它所需要的只是使用

io.once('connection', ...)

代替

io.on('connection', ...)

@brandonraphael您能否提供一个示例来重现您的问题(例如,基于https://github.com/darrachequesne/socket.io-fiddle)并打开一个新的问题?

任何更新仍在发生,并在应用程序中产生问题

这些是日志-
0 | Api服务器| 连接的!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DKap3hUYFSpKBRr7AFgc 4351 2018-12-26 10:58:25
0 | Api服务器| 连接的!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VS98DBFVTNF6ifzmAFgd 4351 2018-12-26 10:58:25

4351是用户标识,并且连接数也不是静态的,就像用户4351的情况一样为2。
另一个日志同时显示同一用户的6个连接。

另外,检查了服务器上的这两个套接字ID,它们显示有效。 但是前端只能监听其中一个,它始终是第一个套接字ID。

任何帮助都将非常棒。
提前致谢。

按照基本示例,我仍然遇到此问题。

编辑:我发现了一个修复程序,尽管我不确定它是否正确。 本质上,它所需要的只是使用

io.once('connection', ...)

代替

io.on('connection', ...)

这次真是万分感谢

更改客户端上使用的版本后,该问题已解决。 另一个解决方法是使用房间而不是单个套接字ID。 发现每个套接字ID本身都是一个房间,只有要更改的部分是将每个套接字ID放入用户房间的新连接代码。
假设一个用户子弹是User1,然后创建了一个房间User1,并将通过该子弹User1创建的每个新套接字连接都放置在用户User1内。

遇到同样的问题,这让我发疯。 绝对也不会在客户端上重新注册事件侦听器。 在我的设置中,我有一个托管socketio端点的nodejs服务器,也有另一个nodejs服务器充当我的socketio客户端。 诀窍是使用websocket传输连接客户端并使用forceNode 。 防爆

// client side
const socket = io('<url>', {
  transports: ['websocket'],
  forceNode: true,
});

我相信我也遇到同样的问题。 我正在建立一个聊天室,当有人加入聊天室时,我会发出“已加入会议室”消息。

一切都很好,但是如果我离开房间然后第二次进入房间,则会在_twice_发出介绍性消息。 如果我再次离开房间,然后再次进入房间,则会发出3次介绍性消息,依此类推。 到_same_房间的每个_reconnection_都会导致重复的介绍消息。 但是,如果我进入_different_房间,我只会看到一次介绍性消息。

使用io.once('connection', ...)对我不起作用。 实际上,我所有的活动都停止了。

使用“去抖”方法也不起作用。 同样,我的任何活动都没有登记。

最后,使用forceNode: true客户端也不起作用。

我在服务器和客户端上都使用2.2.0 。 我有什么想念的吗?

我想知道同样的问题,但最终,告诉客户端仅连接once有所帮助。

这是我的客户端配置:

var socket = io.connect("http://localhost:3000/test", 
    { upgrade: false, transports: ['websocket'], reconnection: true, forceNew: false});
socket.once('connect', socketConn => {
    socket.on('message', data => {
        console.log(data);
    });
}); 

客户端将只为connect事件注册once ,因此其中的任何其他事件都将被注册一次。 现在,如果服务器崩溃,客户端将尝试重新连接到该服务器,而不会尝试创建新的连接。 一旦从服务器获得响应,它将开始处理消息。

因此,需要在客户端而不是服务器端设置io.once

我正在使用客户端2.1版本。 我发现在我的开发环境中很容易触发它。 每当我的节点服务器重新启动(例如,使用nodemon)时,客户端始终会触发多个重新连接事件,然后甚至进行连接。 但我无法找出根本原因

我正在使用客户端2.1版本。 我发现在我的开发环境中很容易触发它。 每当我的节点服务器重新启动(例如,使用nodemon)时,客户端始终会触发多个重新连接事件,然后甚至进行连接。 但我无法找出根本原因

我也有同样的问题,也使用nodemon本身。 但最终,告诉客户仅连接once有所帮助。
尝试上面我的回复中的代码。 它对我有帮助,每次服务器重新启动时,客户端都会获得新的连接。

我的问题很简单

我在2个选项卡上打开了相同的客户端应用程序。 哎呀

我也有同样的问题。 但是,对我来说,我错误地将客户端处理程序放在socket.on('connection', cb)回调函数中。

这是一个演示片段:

client.js(在node.js中)

const client = require('socket.io-client');
const socket = client('my_endpoint', {
  transports: [ 'websockets' ]
});

socket.on('connect', () => {
  console.log('connected');
  socket.on('myEvent', (message) => {
    console.log(`message: ${message}`);
  });
});

当发生断开连接和重新连接时,它将再次调用socket.on('connect', cb) ,并且myEvent处理程序将注册另一个同名处理程序。 因此,当服务器再次发出myEvent时,我将获得两条带有相同消息的控制台日志。

为了解决该问题,我不得不将其他处理程序放在connect处理程序之外。

const client = require('socket.io-client');
const socket = client('my_endpoint', {
  transports: [ 'websockets' ]
});

socket.on('connect', () => {
  console.log('connected');
});

socket.on('myEvent', (message) => {
  console.log(`message: ${message}`);
});

我认为我的困惑来自文档如何显示服务器端将socket.on事件放入connect事件中。 这是因为我没有更仔细地阅读文档,但是我认为我将其放在此处,以防其他人犯同样的错误。

另外,即使我在node.js中特别看到了此问题,我也确信这也是浏览器中的问题。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

dmuth picture dmuth  ·  3评论

stnwk picture stnwk  ·  4评论

adammw picture adammw  ·  4评论

doughsay picture doughsay  ·  4评论

MyMomSaysIAmSpecial picture MyMomSaysIAmSpecial  ·  4评论