在保持套接字连接,但在我的程序中没有执行其他活动时,我间歇性地(但相当一致地)看到浏览器控制台中抛出异常,从 socket.io 机器内部(特别是在backo2/index.js
第 83 行。该错误是:
WebSocket is already in CLOSING or CLOSED state.
我打开了两个选项卡,其中客户端套接字通过 https 连接到同一服务器(本地主机)。 两个客户端都处于空闲状态,浏览器或服务器中没有任何其他事情发生(除了保持活动状态的 pings socket.io 正在做的事情)。 他们都加入了一个单一的频道(通过服务器上的join(..)
)。 否则,没有什么特别的。
以下是我创建服务器套接字实例的方法:
var httpsServer = https.createServer(..);
var io = require("socket.io")(httpsServer);
io.on("connection",onSocketConnection);
在客户端:
socket = io();
socket.on("connect",function(){
console.log("socket connected");
});
socket.on("disconnect",function(){
console.log("socket disconnected");
});
我希望不时断开连接和重新连接,但是当我没有对连接执行任何其他操作时,我不希望库抛出虚假的 JS 异常。
扩展堆栈跟踪:
index.js:83 WebSocket is already in CLOSING or CLOSED state.
(anonymous) @ index.js:83
e.encodePacket @ index.js:83
(anonymous) @ index.js:83
r.write @ index.js:83
r.send @ index.js:83
r.flush @ index.js:83
r.sendPacket @ index.js:83
r.ping @ index.js:83
(anonymous) @ index.js:83
setTimeout (async)
r.setPing @ index.js:83
r.onPacket @ index.js:83
(anonymous) @ index.js:83
r.emit @ index.js:83
r.onPacket @ index.js:83
r.onData @ index.js:83
ws.onmessage @ index.js:83
遇到完全相同的问题并且代码是正确的。 对我来说,这只发生在 Chrome 中。 Mozilla 很干净。 在 chrome 中,这个错误一遍又一遍地重复我的所有聊天记录。 我尝试使用这种方法socket.on('disconnect', () =>{
socket.disconnect();
});
它不会断开客户端与服务器的连接。 回购以备不时之需https://github.com/antoniab123456/Chat_app
这里同样的问题
浏览器只是空闲,然后出现错误。
我使用 Chrome 和 mac OS
是的,伙计们,有人可以解决这个问题吗? 也许我们需要另一行代码来解决这个问题?
我对 socket.io 和 Chrome 有同样的问题
Mac OS 10.13.5
Chrome 版本 67.0.3396.87(官方版本)(64 位)
节点:10.3.0
快递:4.16.3
套接字.io:2.1.1
在 Firefox 中一切都很好。
错误详情如下:
index.js:83 WebSocket is already in CLOSING or CLOSED state.
(anonymous) | @ | index.js:83
| e.encodePacket | @ | index.js:83
| (anonymous) | @ | index.js:83
| r.write | @ | index.js:83
| r.send | @ | index.js:83
| r.flush | @ | index.js:83
| r.sendPacket | @ | index.js:83
| r.ping | @ | index.js:83
| (anonymous) | @ | index.js:83
| setTimeout (async) | |
| r.setPing | @ | index.js:83
| r.onPacket | @ | index.js:83
| (anonymous) | @ | index.js:83
| r.emit | @ | index.js:83
| r.onPacket | @ | index.js:83
| r.onData | @ | index.js:83
| ws.onmessage | @ | index.js:83
当我点击 index.js:83 时,它会将我带到这个模块:
/**
* Expose `Backoff`.
*/
module.exports = Backoff;
/**
* Initialize backoff timer with `opts`.
*
* - `min` initial timeout in milliseconds [100]
* - `max` max timeout [10000]
* - `jitter` [0]
* - `factor` [2]
*
* <strong i="16">@param</strong> {Object} opts
* <strong i="17">@api</strong> public
*/
function Backoff(opts) {
opts = opts || {};
this.ms = opts.min || 100;
this.max = opts.max || 10000;
this.factor = opts.factor || 2;
this.jitter = opts.jitter > 0 && opts.jitter <= 1 ? opts.jitter : 0;
this.attempts = 0;
}
/**
* Return the backoff duration.
*
* <strong i="18">@return</strong> {Number}
* <strong i="19">@api</strong> public
*/
Backoff.prototype.duration = function(){
var ms = this.ms * Math.pow(this.factor, this.attempts++);
if (this.jitter) {
var rand = Math.random();
var deviation = Math.floor(rand * this.jitter * ms);
ms = (Math.floor(rand * 10) & 1) == 0 ? ms - deviation : ms + deviation;
}
return Math.min(ms, this.max) | 0;
};
/**
* Reset the number of attempts.
*
* <strong i="20">@api</strong> public
*/
Backoff.prototype.reset = function(){
this.attempts = 0;
};
/**
* Set the minimum duration
*
* <strong i="21">@api</strong> public
*/
Backoff.prototype.setMin = function(min){
this.ms = min;
};
/**
* Set the maximum duration
*
* <strong i="22">@api</strong> public
*/
Backoff.prototype.setMax = function(max){
this.max = max;
};
/**
* Set the jitter
*
* <strong i="23">@api</strong> public
*/
Backoff.prototype.setJitter = function(jitter){
this.jitter = jitter;
};
//////////////////
// WEBPACK FOOTER
// ./~/backo2/index.js
// module id = 41
// module chunks = 0
第 83 行是:
this.jitter = jitter;
我在使用 backo2.js 和第 83 行时遇到了同样的问题。这是我的错误:
index.js:83 未捕获的类型错误:无法在“FileReader”上执行“readAsArrayBuffer”:参数 1 不是“Blob”类型。
在 n (index.js:83)
在 n (index.js:83)
在 n (index.js:83)
在 n (index.js:83)
在 n (index.js:83)
在 n (index.js:83)
在 Object.e.removeBlobs (index.js:83)
在 s (index.js:83)
在 r.encode (index.js:83)
在 r.packet (index.js:83)
不要担心其他的东西,它们都在第 83 行,即this.jitter = jitter;
这让我非常恼火,因为谷歌实际上没有任何解决方案。
有没有人找到临时解决方案? @antoniab123456您是否能够修复您的聊天应用程序,使其不会重复您的聊天? 它对我做同样的事情。
设置
操作系统:Mac OSX
浏览器:Chrome 67.0.3396.99(官方版本)(64 位)
节点 v10.5.0
Socket.io v2.1.1
我正面临着 chrome 中提到的@getify的确切问题。 有没有人找到解决这个问题的方法?
同样的问题。 有人可以对此作出回应吗?
同样的问题。
设置
操作系统:Mac OSX
浏览器:Chrome 67.0.3396.99(官方版本)(64 位),Node 9.6.1
socket.io 版本:2.1.1
@19smitgr idk 你所说的“重复聊天”是什么意思,这听起来离题,如果你的意思是“同一屏幕上的重复消息”,可以通过广播来解决。
@kino2007我不是在制作聊天应用程序。 我实际上是在多人游戏中使用 websockets,并且 websocket 没有收到断开消息,所以当用户由于每个人都在谈论的随机错误而断开连接并重新连接时,它会给角色一个新的套接字 ID,并且具有旧套接字 ID 的旧精灵没有被删除,因为它只是收到“传输关闭”消息而不是“断开连接”消息。
此时,即使我收到“传输关闭”消息,我也会从当前用户列表中删除该用户,就像收到“断开连接”消息一样。
我为我修好了:
以前我用这个:
socket.on('ping', alert);
但后来我把它改成这样:
socket.on('ping', msg => {
alert(msg);
});
它奏效了!
我有同样的问题。 对此有何更新?
同样在这里。
socket.io & socket.io-client: "^2.1.1"
苹果系统
谷歌浏览器是最新的
版本 68.0.3440.106(官方版本)(64 位)
我有同样的问题。 此外,它正在复制我从服务器发送到客户端的消息。
macOS:10.13.6
Socket.io:“^2.1.1”
铬:68.0.3440.106
@abhyuditjain您可以尝试使用socket.removeAllListeners();
重置所有侦听器,以避免可能导致重复消息的多个侦听器注册。
对于几个人来说,这似乎是一个持续存在的问题,并且没有任何解决方案。 任何人的任何更新?
@vkotu如果我删除所有侦听器,则套接字在断开连接时不会重新连接到服务器。 有任何解决这个问题的方法吗?
只需使用 websocket-node,它很容易使用并且没有任何错误,而且你不需要外部库:
https://codeburst.io/why-you-don-t-need-socket-io-6848f1c871cd
https://medium.com/@martin.sikora/node -js-websocket-simple-chat-tutorial-2def3a841b61
https://www.npmjs.com/package/websocket
不是广告,只是帮助,除非您对此错误做出决定:DDD 它已经持续了几个月 05.09.2018,13:15,“Abhyudit Jain”通知@github.com :@antoniab123456此页面用于发布有关此的问题存储库。 请不要在这里做广告。
- 您收到此邮件是因为您被提及。直接回复此电子邮件,在 GitHub 上查看它,或将线程静音。
-- 此致 Antonia B. 客户服务专家@amoCRM Global
降级到2.0.3
为我“修复”了这个问题。
@cozuya将对其进行测试。 会告诉你它是否有效!
降级到
2.0.3
为我“修复”了这个问题。
似乎在做这个把戏。 测试了 4 分钟,没有错误。 看看能坚持多久!
@cozuya感谢您发布此信息!
2.1.1 中的相同错误
降级到 2.0.3 为我“修复”了这个问题。
2.0.3 对我有用! 谢谢@cozuya
2.1.1 仍然面临同样的问题。 尝试增加 ping 和超时,但没有任何改变
chrome 与 v2.1.1 有同样的问题,而浏览器闲置了很长时间(大约 20-30 分钟)
2.1.1 仍然面临同样的问题。 尝试增加 ping 和超时,但没有任何改变
降级到 v 2.0.3
我曾尝试将 socket.io 与 2.0.4 一起使用,它看起来很正常。
我发现 pingTimeout 从 60000(v2.0.4) 更改为 5000 (v2.1.1)
如果我将 pingTimeout 更改为更大的数字,例如 10000 秒,它似乎可以工作。
我想这可能与浏览器空闲有关,其中非活动选项卡会有一些限制。
我遇到了一些问题。有人解决了这个问题吗?
我也不得不降级。 它不适用于 chrome 和 safari
这里同样的问题。 OSX 下的 Chrome。
除了"disconnect"
等之外,我对所有非技术听众都使用socket.removeAllListeners();
socket.off("whatever")
来解决它。 工作正常。 浏览器控制台中的错误消息很烦人,但对我来说不值得降级。
我不得不说,在没有任何关注的情况下看到这个问题是令人失望的。 现在是六个月,而且还在继续。
所以重新连接的原因对我来说是 ping 超时。 即使降级,我仍然收到错误。
我完全同意这样一个庞大的库,拥有丰富的代码库,却没有注意到这个问题!
希望有人能尽快解决!
从我的iPhone发送
2018 年 11 月 28 日下午 2:14,HorseBadorties通知@github.com 写道:
这里同样的问题。 OSX 下的 Chrome。
我不使用 socket.removeAllListeners(); 但 socket.off("whatever") 对于我所有的非技术听众,除了“断开连接”等等。 工作正常。 浏览器控制台中的错误消息很烦人,但对我来说不值得降级。
我不得不说,在没有任何关注的情况下看到这个问题是令人失望的。 现在是六个月,而且还在继续。
—
您收到此消息是因为您发表了评论。
直接回复此电子邮件,在 GitHub 上查看它,或将线程静音。
同样的问题....很惊讶尚未对此进行修复。
我遇到了这个问题。 在我的情况下,断开连接是由于ping timeout
。 但是,客户端停止响应 ping 的原因没有运气。
io.on('connection', function(socket) {
socket.on('disconnect', function(reason) {
console.log(`Socket disconnected for: ${reason}`);
}
});
https://socket.io/docs/server-api/#Event -%E2%80%98disconnect%E2%80%99 列出了断开连接的原因。
更多调试:
一个观察结果是客户端上的ping
事件与上一个事件相差+30s
。 每次我看到断开连接时,它都是30s+
,这是默认的心跳间隔 + ping 超时。 +26s
、 +28s
和+29s
确实没有断开连接。
与 Safari 进行比较时,Safari 在每25s
一次 ping 方面更加一致,并且没有发现任何断开连接。
默认 pingTimeout 从 60000(v2.0.4) 更改为 5000 (v2.1.0+),这对于 Chrome 等某些浏览器来说还不够。
在 v2.1.0+ (包括最新的 v2.2.0)上解决此问题的方法是将服务器上的默认 pingTimeout 覆盖为一个较大的值,如下所示:
const http = require('http');
const server = http.createServer();
const io = require('socket.io')(server, {
pingTimeout: 60000,
});
要么
const io = require('socket.io')();
const http = require('http');
const server = http.createServer();
io.attach(server, {
pingTimeout: 60000,
});
为什么5000不够? 我在本地开发服务器上看到了这个问题,并且客户端和服务器之间的延迟肯定低于该阈值。 5000 毫秒似乎是一个合理的超时。 闻起来像是乒乓球系统本身可能有问题,只有在降低时才会显现出来。
感谢启动这个线程@getify (我在socket.io v2.2.0上)
对于同样遇到这种情况的任何人-我也评论没有帮助:-)请用拇指投票以表示您的支持👍
感谢@omardoma发现pingTimeout
,我同意@LunarMist我们应该调查ping/pong
事件系统。
我用 Chrome、Firefox 和 Safari(都在 MacOS 上)做了一些初步测试。
Chrome和Safari似乎都以不同的行为和约束来限制 ws 活动:
我用所有 3 种浏览器测试了几个小时,更改了pingTimeout
和pingInterval
值。 我发现的解决方案是:
pingTimeout
>= 30000
毫秒pingInterval
<= 10000
毫秒我相信最好的解决方案是改变pingTimeout = 30000
。 默认的pingInterval
是25000
毫秒,并且将客户端 ping 服务器的频率提高到每 10 秒对于 _at scale_ 项目来说太麻烦了。
@darrachequesne或任何其他 repo 成员是否赞成将默认pingTimeout
30000
从当前默认5000
ms 增加到 30000 毫秒,在 v2.1 中从60000
更改
对您自己的评论做出反应也无济于事。
客户端是 ping 服务器的,而不是相反的。
我认为这是因为当前版本的 socket.io 依赖于客户端的 setTimeout,这可能不如预期的那么可靠。
我认为增加pingTimeout
应该可以暂时解决这个问题,但我们将在 v3 中使用来自服务器 -> 客户端(而不是当前客户端 -> 服务器)的 ping/pong。
只需在客户端使用以下代码。
_socket.on('ping', () => {
socket.emit(数据);
});_
谢谢@crobinson42! Ping 超时解决方案对我来说非常有用。 我只是对该解决方案有些担忧。 如果您在任何时候失去互联网连接,最多需要 30 秒才能触发断开连接事件,对于某些应用程序来说,这太多了。 例如,想要在用户未连接时禁用文本输入的聊天应用程序。
在这种情况下,增加 ping 间隔就可以了,但正如你所说,成本很高,有什么解决方法吗?
一旦这个问题得到解决,请让我们知道,对我来说同样的问题,我的版本如下:
"socket.io": "2.2.0",
"socket.io-adapter": "~1.1.1",
"socket.io-client": "2.2.0",
"socket.io-parser": "~3.2.0",
"socket.io-redis": "^5.2.0",
我的代码:
服务器, {
路径:'/socket.io',
服务客户端:真,
// 下面是 engine.IO 选项
pingInterval: 40000,
ping超时:25000,
upgradeTimeout: 30000, // 默认值是10000ms,试试改成20k以上
代理:假,
饼干:假,
拒绝未授权:假,
重新连接延迟:1000,
重新连接延迟最大:5000
}
我的客户:
重新连接:真,
重新连接延迟:1000,
重新连接延迟最大:5000,
重新连接尝试:无限,
//我们的网站选项
传输:[“轮询”,“websocket”],
安全:真实,
拒绝未授权:假,
forceNew:真的,
超时:60000
你好法赞,
您可以让此代码运行为 -
** 我使用的版本与您提供的相同..
服务器端 - 代码:
const server = require('http').createServer();
const io = 要求('socket.io')(服务器,{
// 路径:'/socket.io',
服务客户端:真,
pingInterval: 40000,
pingTimeout: 25000,
upgradeTimeout: 21000, // default value is 10000ms, try changing it to 20k or more
agent: false,
cookie: false,
rejectUnauthorized: false,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000
});
io.on('连接', function(socket) {
socket.emit('welcome', { message: 'Welcome!', id: socket.id });
socket.on('Sunil', console.log);
});
server.listen(3000);
客户端代码:
var client = require("socket.io-client");
var socket = client.connect("http://localhost:3000", {
重新连接:真,
重新连接延迟:1000,
重新连接延迟最大:5000,
重新连接尝试:无限,
传输:[“websocket”],
安全:假,
拒绝未授权:假,
forceNew:真的,
超时:6000
});
socket.connect();
socket.emit('Sunil', {
数据:'你好'
});
socket.on('欢迎',函数(数据){
控制台日志(数据)
socket.emit('Sunil', {
数据:'Faizan',
id:数据.id
});
socket.disconnect();
});
问候
苏尼尔·亚达夫
2019 年 5 月 9 日下午 4:05,Faizan Zahid [email protected]写道:
重新连接:真,
重新连接延迟:1000,
重新连接延迟最大:5000,
重新连接尝试:无限,
//我们的网站选项
传输:[“轮询”,“websocket”],
安全:真实,
拒绝未授权:假,
forceNew:真的,
超时:60000
如果在问题得到解决之前有人感兴趣,可能是客户端的一种解决方法。 这将导致浏览器无法释放内存,并可能导致内存使用过多。
defaults write com.apple.Safari IncludeInternalDebugMenu 1
如果有人有 Chrome 解决方法,那将有所帮助
您将 Safari 用于 localhost webdev? 🤔
您将 Safari 用于 localhost webdev? 🤔
不是真的,但是不断断开连接来测试我的应用程序很烦人。 这提供了一个临时解决方法,直到它在 3.0 中得到修复。 这不是解决方案。 我发布了它是否会在开发期间帮助某人。
我正在使用非常低的 pingInterval 和 pingTimeouts 来获取实时离线状态更改,将其设置为 30 秒会破坏我的流程......有人知道解决这个问题的方法,所以我可以对后台浏览器使用长超时“修复”标签?
对此有何更新?
我正在使用非常低的 pingInterval 和 pingTimeouts 来获取实时离线状态更改,将其设置为 30 秒会破坏我的流程......有人知道解决这个问题的方法,所以我可以对后台浏览器使用长超时“修复”标签?
您应该是套接字上的断开事件来处理存在,当套接字断开连接时,找到用户并将其标记为在您的数据存储中离线
以下是文档中的默认值。 看起来每 25 秒发送一次 ping,每个 ping 有 5 秒完成。
ping超时 | 5000 | 没有 pong 数据包的毫秒数认为连接已关闭
-- | -- | --
ping 间隔 | 25000 | 发送新的 ping 数据包前多少毫秒
我注意到了同样的错误,但在不同的上下文中,所以我将快速写下我的问题和解决方案,以供其他任何人在这里结束。
我的场景是在 Chrome for Android 上锁定屏幕后断开连接。
我使用令牌来识别不同连接中的同一用户,我使用查询选项方法在连接时从客户端发送该令牌,并使用从服务器接收到的新令牌更新令牌:
// client
io('myAppUrl', {
query: {
token: localStorage.getItem('myKey') || ''
}
});
io.on('reconnect_attempt', () => {
io.opts.query = {
token: localStorage.getItem('myKey') || ''
};
});
io.on('my_custom_connection_successful_event', (token) => {
localStorage.setItem('myKey', token);
});
问题是 Chrome for Android 客户端会在重新连接时向服务器发送一个空字符串令牌。 这是我没想到的,因为我添加了'reconnect_attempt'
监听器,它确保从localStorage
设置最新的令牌。
在使用控制台记录所有可能的客户端事件进行了几个小时的调试之后,我意识到在我重新连接的情况下根本没有触发'reconnect_attempt'
事件。 解锁屏幕后,我得到以下事件序列:
所以没有'reconnect_attempt'
事件被触发,这解释了为什么令牌仍然是空字符串(连接时设置的初始值)。
长话短说,我的解决方案是立即使用新令牌从服务器接收到的自定义“连接成功”事件上的io.opts.query
实例变量更新:
// client
io('myAppUrl', {
query: {
token: localStorage.getItem('myKey') || ''
}
});
io.on('my_custom_connection_successful_event', (token) => {
localStorage.setItem('myKey', token);
io.opts.query = {
token: token
};
});
现在我明白io.opts.query
是一个实例变量,用于连接和所有后续重新连接,所以我可以随时更新它。 我不必等待任何与重新连接相关的事件。
我觉得With query options文档有点误导。 也许我误解了那个例子中的用例? 但是,如果它类似于我的用例,而不是'reconnect_attempt'
示例,文档可以解释io.opts.query
是一个可以变异的实例变量,并且它的当前值用于所有后续重新连接。 因此,只要您想刷新令牌,就可以更改它,即使在'refresh_token'
自定义事件中也是如此。 如果您认为改进文档是个好主意,我可以做 PR。
编辑:
经过进一步调查,我意识到我的错误是'reconnect_attempt'
侦听器已从我的代码的另一部分中删除... :man_facepalming: 这就是我在日志中没有看到它的原因。 所以是的,我的重新连接场景的事件顺序实际上是:
尽管如此,我意识到可以随时更改io.opts.query
仍然有效。 :sweat_smile:
降级还可以吗? 我打开 2.0.3 但它似乎不起作用。
您好,我遇到了同样的问题,但有两个错误。 我尝试了@omardoma解决方案。 任何人都可以帮忙吗?
操作系统 - Ubuntu 18.04
节点 - 12.16.2
npm - 6.14.5
socket.io - 2.3.0
我的代码 -
应用程序.js
const speech = require('@google-cloud/speech');
const speechClient = new speech.SpeechClient(); // Creates a client
const environmentVars = require('dotenv').config();
const io = require('socket.io')();
const http = require('http');
const server = http.createServer();
io.attach(server, {
pingTimeout: 60000,
});
console.log(io)
// =========================== SOCKET.IO ================================ //
io.on('connection', function (client) {
console.log('Client Connected to server');
let recognizeStream = null;
.ejs 文件
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js" integrity="sha256-bQmrZe4yPnQrLTY+1gYylfNMBuGfnT/HKsCGX+9Xuqo=" crossorigin="anonymous"></script>
<script src="/js/client.js"></script>
js文件
const socket = io.connect("http://localhost:8080");
我正在使用 socket.io 2.3.0 版。 我使用 websocket 连接到客户端。 当我的客户端在 UI 中有浏览器警报(同步)并且如果用户在超过 30 秒(pingTimeout + pingInterval)内没有解除警报时,我会看到“Websocket 已处于 CLOSING 或 CLOSED 状态”消息并获得具有 pingTimeout 原因的断开事件。 当 UI 有警报时,我不希望此 websocket 断开连接。 如果我将 pingTimeout 增加到 10 分钟,则断开连接不会发生 10 分钟。 但是从我在上面的评论中看到的,这可能会产生负面影响(客户可能直到 10 分钟才知道断开连接)。 但我注意到,如果出现网络中断等情况,我们会因传输关闭原因而断开连接。 那么增加这个pingTimeout+pingInterval可以吗? 未检测到断开连接时是否存在特定情况? 或者有没有其他方法可以解决这个问题?
最有用的评论
默认 pingTimeout 从 60000(v2.0.4) 更改为 5000 (v2.1.0+),这对于 Chrome 等某些浏览器来说还不够。
在 v2.1.0+ (包括最新的 v2.2.0)上解决此问题的方法是将服务器上的默认 pingTimeout 覆盖为一个较大的值,如下所示:
要么