提问者:小点点

如何调试Node.js中的ECONNRESET错误?


我正在运行一个Express.js应用程序,使用socket.io作为一个聊天webapp,在24小时内我随机地出现了大约5次以下错误。节点进程永远包装在里面,并且它会立即重新启动自己。

问题是,重启Express会把我的用户踢出他们的房间,而没有人希望这样。

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

这是节点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的stacktrace:

    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)

这会是原因吗?


共3个答案

匿名用户

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

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

但是由于您也在寻找检查错误并潜在地调试问题的方法,因此您应该看一看“如何在NodeJS中调试套接字挂起错误?”这篇文章发表在stackoverflow上,与一个类似的问题有关。

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

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

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

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

编辑(2013-07-22)

正如我上面写的:

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

这种情况也可能是:在随机的时候,另一端负载过重,结果只是扼杀了连接。如果是这样的话,那就要看你连接到什么了…

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

匿名用户

我为闪存策略文件提供服务的一个简单的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)

匿名用户

我也遇到过类似的问题,在升级Node之后,应用程序开始出错。我相信这可以追溯到Node release V0.9.10这一项:

  • net:不抑制ECONNRESET(Ben Noordhuis)

以前的版本不会在客户机中断时出错。来自客户端的连接中断会在Node中引发错误ECONNRESET。我相信这是Node的预期功能,所以修复(至少对我来说)是处理错误,我相信您在未捕获的异常中做了这件事。尽管我在Net.Socket处理程序中处理它。

您可以演示以下内容:

制作一个简单的套接字服务器并获取节点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键)

在使用节点V0.9.9时应该不会出现错误,而在使用节点V0.9.10及更高版本时则会出现错误。

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