node.js - nodejs - socket read econnreset




節點js ECONNRESET (8)

今天有同樣的問題。 經過一番研究,我發現了一個非常有用--abort-on-uncaught-exception node.js選項 。 它不僅提供了更詳細和有用的錯誤堆棧跟踪,而且還可以在應用程序崩潰時保存核心文件,以便進一步調試。

我運行一個Express js應用程序,使用socket.io進行聊天web應用程序,並在24小時內隨機獲得以下錯誤大約5次。 節點進程被永久封裝並立即重新啟動。

問題在於重新啟動快速將我的用戶踢出他們的房間,而沒有人希望這樣。

Web服務器由HAProxy代理。 沒有套接字穩定性問題,只使用websocket和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”的堆棧跟踪:

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)

這可能是原因嗎?


你可能已經猜到了:這是一個連接錯誤。

“ECONNRESET”意味著TC​​P對話的另一端突然關閉連接的結束。 這很可能是由於一個或多個應用程序協議錯誤。 您可以查看API服務器日誌以查看它是否抱怨某些事情。

但是因為你也在尋找一種方法來檢查錯誤並且可能調試問題,所以你應該看看“ 如何在NodeJS中調試一個套接字掛起錯誤? ” ,這是在一個相似的問題上發佈在上的。

快速和骯髒的開發解決方案

使用longjohn ,會得到包含異步操作的長堆棧跟踪。

清理和正確的解決方案 :從技術上講,在節點中,每當發出'error'事件並且沒有人聽它時,它就會拋出 。 為了讓它不扔,把一個聽眾放在它上面,並自己處理。 這樣,您可以使用更多信息記錄錯誤。

要為一組調用擁有一個偵聽器,您可以使用domains並在運行時捕獲其他錯誤。 確保與http(服務器/客戶端)相關的每個異步操作與代碼的其他部分處於不同的domains環境中,域將自動偵聽error事件並將其傳播到它自己的處理程序。 所以你只能聽那個處理程序並獲取錯誤數據。 您還可以免費獲得更多信息。

編輯(2013-07-22)

正如我上面寫的:

“ECONNRESET”意味著TC​​P對話的另一端突然關閉連接的結束。 這很可能是由於一個或多個應用程序協議錯誤。 您可以查看API服務器日誌以查看它是否抱怨某些事情。

還有可能是這樣的:在隨機時間,另一方負載過重,結果導致連接中斷。 如果是這樣的話,取決於你連接到什麼......

但有一點是肯定的:你的TCP連接確實有讀取錯誤,導致異常。 您可以通過查看您在編輯中發布的錯誤代碼來確認它。


嘗試將這些選項添加到socket.io中:

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

我希望這能幫到您 !


我也有這個錯誤,並且經過幾天的調試和分析後能夠解決它:

我的解決方案

對我來說VirtualBox(對於Docker)是個問題。 我在我的虛擬機上配置了端口轉發,並且錯誤僅出現在轉發的端口上。

一般結論

以下觀察可以為您節省我不得不投資的工作天數:

  • 對我來說,這個問題只發生在一個端口上從本地主機到本地主機的連接上。 - >檢查改變任何這些常量解決了這個問題。
  • 對我來說,這個問題只發生在我的機器上 - >讓其他人嘗試它。
  • 對我而言,問題只會在一段時間後出現,無法可靠地再現
  • 我的問題不能用任何節點或表達(調試)工具來檢查。 - >不要在此浪費時間

- >弄清楚虛擬機,防火牆等網絡是否有問題(設置),這可能是問題的原因。


我有一個類似的問題,應用程序在升級Node後出現錯誤。 我相信這可以追溯到Node發布v0.9.10這個項目:

  • 網絡:不要壓制ECONNRESET(Ben Noordhuis)

以前的版本不會因客戶端的中斷而出錯。 來自客戶端的連接中斷會引發節點中的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。 東西,它仍然給出了錯誤。 再次,我認為這是有意的,解決方案是處理代碼中的錯誤。


我用來提供Flash策略文件的一個簡單的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)

我面臨同樣的問題,但我通過下列方式減輕了這個問題:

server.timeout = 0;

server.listen之前。 服務器在這裡是一個HTTP服務器。 根據API文檔 ,默認超時為2分鐘。


是的,您提供的政策文件肯定會導致崩潰。

重複一遍,只需在代碼中添加延遲:

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() { console.log("error"); });
  socket.write("<?xml version=\"1.0\"?>\n")

當您嘗試上述斷開連接時,您只會收到日誌消息而不是崩潰。

當你完成時,記得要消除延遲。







express