366

我正在使用 Socket.io 为聊天 webapp 运行 Express.js 应用程序,并且在 24 小时内随机出现大约 5 次以下错误。节点进程被永远包裹起来,它会立即重新启动。

问题是重新启动 Express 会将我的用户踢出他们的房间,而没有人想要这样。

Web 服务器由 HAProxy 代理。没有套接字稳定性问题,只使用 websockets 和 flashsockets 传输。我不能故意复制这个。

这是 Node 的错误v0.10.11

    events.js:72
            throw er; // Unhandled 'error' event
                  ^
    Error: read ECONNRESET     //alternatively it s a 'write'
        at errnoException (net.js:900:11)
        at TCP.onread (net.js:555:19)
    error: Forever detected script exited with code: 8
    error: Forever restarting script for 2 time

编辑 (2013-07-22)

添加了 socket.io 客户端错误处理程序和未捕获的异常处理程序。似乎这个抓住了错误:

    process.on('uncaughtException', function (err) {
      console.error(err.stack);
      console.log("Node NOT Exiting...");
    });

所以我怀疑这不是 Socket.io 问题,而是对我所做的另一台服务器的 HTTP 请求或 MySQL/Redis 连接。问题是错误堆栈不能帮助我识别我的代码问题。这是日志输出:

    Error: read ECONNRESET
        at errnoException (net.js:900:11)
        at TCP.onread (net.js:555:19)

我怎么知道是什么原因造成的?如何从错误中获得更多信息?

好的,不是很冗长,但这是 Longjohn 的堆栈跟踪:

    Exception caught: Error ECONNRESET
    { [Error: read ECONNRESET]
      code: 'ECONNRESET',
      errno: 'ECONNRESET',
      syscall: 'read',
      __cached_trace__:
       [ { receiver: [Object],
           fun: [Function: errnoException],
           pos: 22930 },
         { receiver: [Object], fun: [Function: onread], pos: 14545 },
         {},
         { receiver: [Object],
           fun: [Function: fireErrorCallbacks],
           pos: 11672 },
         { receiver: [Object], fun: [Function], pos: 12329 },
         { receiver: [Object], fun: [Function: onread], pos: 14536 } ],
      __previous__:
       { [Error]
         id: 1061835,
         location: 'fireErrorCallbacks (net.js:439)',
         __location__: 'process.nextTick',
         __previous__: null,
         __trace_count__: 1,
         __cached_trace__: [ [Object], [Object], [Object] ] } }

在这里,我提供闪存套接字策略文件:

    net = require("net")
    net.createServer( (socket) =>
      socket.write("<?xml version=\"1.0\"?>\n")
      socket.write("<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n")
      socket.write("<cross-domain-policy>\n")
      socket.write("<allow-access-from domain=\"*\" to-ports=\"*\"/>\n")
      socket.write("</cross-domain-policy>\n")
      socket.end()
    ).listen(843)

这可能是原因吗?

4

16 回答 16

325

您可能已经猜到了:这是一个连接错误。

“ECONNRESET”表示 TCP 会话的另一端突然关闭了它的连接端。这很可能是由于一个或多个应用程序协议错误造成的。您可以查看 API 服务器日志以查看它是否抱怨某些问题。

但是,由于您也在寻找一种方法来检查错误并可能调试问题,因此您应该查看如何在 NodeJS 中调试套接字挂起错误?,它发布在 stackoverflow 上,与一个类似的问题有关。

快速而肮脏的开发解决方案

使用 longjohn,您将获得包含异步操作的长堆栈跟踪。

干净和正确的解决方案:从技术上讲,在节点中,每当你发出一个'error'事件并且没有人听它时,它就会抛出. 为了让它不抛出,在它上面放一个监听器并自己处理它。这样,您可以使用更多信息记录错误。

要为一组调用设置一个侦听器,您可以使用 并在运行时捕获其他错误。确保与 http(Server/Client) 相关的每个异步操作与代码的其他部分相比位于不同的error上下文中,域将自动侦听事件并将其传播到它自己的处理程序。所以你只听那个处理程序并获取错误数据。您还可以免费获得更多信息。

编辑 (2013-07-22)

正如我上面写的:

“ECONNRESET”表示 TCP 会话的另一端突然关闭了它的连接端。这很可能是由于一个或多个应用程序协议错误造成的。您可以查看 API 服务器日志以查看它是否抱怨某些问题。

也可能是这种情况:在随机时间,另一端过载并因此简单地终止连接。如果是这种情况,则取决于您要连接的确切内容……</p>

但有一件事是肯定的:您的 TCP 连接上确实存在读取错误,这会导致异常。您可以通过查看您在编辑中发布的错误代码来确认这一点。

于 2013-07-14T08:53:45.283 回答
49

我为提供闪存策略文件而使用的一个简单的 tcp 服务器导致了这种情况。我现在可以使用处理程序捕获错误:

# serving the flash policy file
net = require("net")

net.createServer((socket) =>
  //just added
  socket.on("error", (err) =>
    console.log("Caught flash policy server socket error: ")
    console.log(err.stack)
  )

  socket.write("<?xml version=\"1.0\"?>\n")
  socket.write("<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n")
  socket.write("<cross-domain-policy>\n")
  socket.write("<allow-access-from domain=\"*\" to-ports=\"*\"/>\n")
  socket.write("</cross-domain-policy>\n")
  socket.end()
).listen(843)
于 2013-07-23T08:38:09.077 回答
33

我有一个类似的问题,即在升级 Node.js 后应用程序开始出错。我相信这可以追溯到Node release v0.9.10这个项目:

  • net: 不要压制 ECONNRESET (Ben Noordhuis)

以前的版本不会因客户端的中断而出错。来自客户端的连接中断会在 Node.js 中引发错误 ECONNRESET。我相信这是 Node 的预期功能,所以修复(至少对我来说)是处理错误,我相信你在未捕获的异常中做了。虽然我在 net.socket 处理程序中处理它。

你可以证明这一点:

制作一个简单的套接字服务器并获得 Node v0.9.9 和 v0.9.10。

require('net')
    .createServer( function(socket) 
    {
           // no nothing
    })
    .listen(21, function()
     {
           console.log('Socket ON')
    })

使用 v0.9.9 启动它,然后尝试 FTP 到该服务器。我使用 FTP 和端口 21 只是因为我在 Windows 上并且有一个 FTP 客户端,但没有方便的 telnet 客户端。

然后从客户端,断开连接。(我只是在做 Ctrl-C)

使用 Node v0.9.9 时应该看到 NO ERROR,使用 Node v.0.9.10 及更高版本时应该看到 ERROR。

在生产中,我使用 v.0.10。一些东西,它仍然给出错误。同样,我认为这是有意的,解决方案是处理代码中的错误。

于 2013-07-22T22:12:50.273 回答
18

今天遇到了同样的问题。经过一番研究,我发现了一个非常有用的--abort-on-uncaught-exceptionnode.js 选项。它不仅提供了更详细和有用的错误堆栈跟踪,而且还保存了应用程序崩溃时的核心文件,以便进一步调试。

于 2015-06-29T18:40:42.533 回答
15

我遇到了同样的问题,但我通过放置来缓解它:

server.timeout = 0;

之前server.listenserver这里是一个 HTTP 服务器。根据API 文档,默认超时为 2 分钟。

于 2014-10-28T05:07:15.677 回答
15

我在开发过程中也遇到了 ECONNRESET 错误,我解决它的方法是使用 nodemon 来启动我的服务器,只是"node server.js"用来启动我的服务器解决了我的问题。

这很奇怪,但它对我有用,现在我再也看不到 ECONNRESET 错误了。

于 2018-04-26T16:18:15.310 回答
10

是的,您提供的策略文件肯定会导致崩溃。

重复一遍,只需在您的代码中添加一个延迟:

net.createServer( function(socket) 
{
    for (i=0; i<1000000000; i++) ;
    socket.write("<?xml version=\"1.0\"?>\n");
…

…并用于telnet连接到端口。如果您在延迟到期之前断开 telnet,当 socket.write 抛出错误时,您将遇到崩溃(未捕获的异常)。

为了避免这里的崩溃,只需在读/写套接字之前添加一个错误处理程序:

net.createServer(function(socket)
{
    for(i=0; i<1000000000; i++);
    socket.on('error', function(error) { console.error("error", error); });
    socket.write("<?xml version=\"1.0\"?>\n");
}

当您尝试上述断开连接时,您只会收到一条日志消息而不是崩溃。

完成后,请记住消除延迟。

于 2013-07-23T09:07:59.247 回答
10

另一种可能的情况(但很少见)可能是您有服务器到服务器的通信并且设置server.maxConnections为非常低的值。

在节点的核心库net.js 中,它会调用clientHandle.close()这也会导致错误 ECONNRESET:

if (self.maxConnections && self._connections >= self.maxConnections) {
  clientHandle.close(); // causes ECONNRESET on the other end
  return;
}
于 2016-10-07T14:32:44.050 回答
6

我也有这个错误,经过几天的调试和分析后能够解决它:

我的解决方案

对我来说,VirtualBox(用于 Docker)是问题所在。我在我的虚拟机上配置了端口转发,错误只发生在转发的端口上。

一般结论

以下观察结果可能会为您节省我必须投入的工作时间:

  • 对我来说,问题只发生在一个端口上从 localhost 到 localhost 的连接上。-> 检查更改这些常量中的任何一个都可以解决问题。
  • 对我来说,问题只发生在我的机器上->让其他人尝试一下。
  • 对我来说,问题只是在一段时间后才出现,并且无法可靠地重现
  • 无法使用任何节点或表达(调试)工具检查我的问题。-> 不要在这上面浪费时间

-> 弄清楚您的网络(-设置)是否有问题,例如虚拟机、防火墙等,这可能是问题的原因。

于 2018-05-04T16:02:07.900 回答
5

当服务器端关闭 TCP 连接并且您对服务器的请求未完成时,会发生ECONNRESET 。服务器响应连接消息,您指的是无效连接。

为什么服务器发送一个无效连接的请求?

假设您启用了客户端和服务器之间的保持连接。保持活动超时配置为 15 秒。这意味着如果keep-alive空闲15秒,它将发送连接关闭请求。所以 15 秒后,服务器告诉客户端关闭连接。但是,当服务器发送此请求时,客户端正在向服务器端发送一个已经在飞行中的新请求。由于此连接现在无效,服务器将拒绝并显示 ECONNRESET 错误。因此,由于对服务器端的请求较少,因此会出现问题。所以请禁用keep-alive,它会正常工作。

于 2021-06-06T06:32:08.327 回答
4

我通过简单地连接到不同的网络解决了这个问题。这是可能的问题之一。

如上所述,ECONNRESET意味着 TCP 会话突然关闭了它的连接端。

您的互联网连接可能会阻止您连接到某些服务器。就我而言,我试图连接到 mLab(托管 MongoDB 数据库的云数据库服务)。我的 ISP 阻止了它。

于 2018-02-10T11:27:35.787 回答
4

我只是想通了这一点,至少在我的用例中。

我得到了ECONNRESET。事实证明,我的客户端的设置方式非常迅速地通过 API 调用多次访问服务器——而且它只需要访问端点一次。

当我修复它时,错误消失了。

于 2020-05-24T00:53:28.447 回答
4

我通过以下方式解决了这个问题:

  • 关闭我的 wifi/以太网连接并打开。
  • 我输入:npm update在终端中更新 npm。
  • 我尝试从会话中注销并再次登录

之后我尝试了相同的 npm 命令,好在它成功了。我不确定它是否那么简单。

我正在使用 CENTOS 7

于 2019-02-25T11:46:04.443 回答
1

我遇到了同样的问题,似乎 Node.js 版本是问题所在。

我安装了以前版本的 Node.js (10.14.2),使用 nvm 一切正常(允许您安装多个版本的 Node.js 并快速从一个版本切换到另一个版本)。

这不是一个“干净”的解决方案,但它可以暂时为您服务。

于 2019-12-19T14:48:41.550 回答
0

Node JS 套接字是非阻塞 io。考虑使用来自其他来源的非阻塞 io 连接。例如,如果您使用带有节点的阻塞 Java 套接字,它只会工作几秒钟,之后将处理错误。通过使用选择器实现非阻塞连接(即套接字通道)来缓解此问题。

于 2021-06-05T05:39:01.010 回答
0

尝试将这些选项添加到 socket.io:

const options = { transports: ['websocket'], pingTimeout: 3000, pingInterval: 5000 };

我希望这能帮到您 !

于 2018-04-19T17:40:31.517 回答