簡體   English   中英

Erlang:如何在Linux上觸發ECONNRESET?

[英]Erlang: How to trigger ECONNRESET on Linux?

我最近遇到的heisenbug般出現ECONNRESET使用Erlang在Mac OS X(不是我的機器!)。 為了簡化問題的根源,並且為了更好地理解錯誤本身,我編寫了以下模塊來觸發ECONNRESET 不幸的是,我自己沒有Mac。 在我的Linux(ArchLinux)上,下面的代碼不會由於{error,econnreset}不匹配而崩潰,而是帶有{error,closed}{error,econnreset}

-module(econnreset).

-export([run/0]).

run() ->
    Pid = spawn_link(fun listen_and_accept/0),
    Pid ! {get_port,self()},
    Port = receive {port,P} -> P end,

    {ok,Socket} = gen_tcp:connect("localhost", Port, [{active,false}]),
    ok = gen_tcp:send(Socket, lists:duplicate(100, $a)),

    %% On the following line, I expected a badmatch w/ {error,econnreset}
    {ok,_} = gen_tcp:recv(Socket, 0, 1000),
    ok = gen_tcp:close(Socket),
    ok.

listen_and_accept() ->
    {ok,LSocket} = gen_tcp:listen(0, [binary,{active,false}]),
    {ok,Port} = inet:port(LSocket),
    receive {get_port,Pid} -> Pid ! {port,Port} end,

    {ok,Socket} = gen_tcp:accept(LSocket),
    {ok,Bin} = gen_tcp:recv(Socket, 1), %=> read only 1 byte to trigger tcp RST
    io:format("Server read ~p~n", [Bin]),
    gen_tcp:close(Socket),
    gen_tcp:close(LSocket).

由於我僅在Mac OS X上而不是Linux上遇到了ECONNRESET ,這歸結為兩個問題:

  1. 上面的代碼是否甚至可以通過調用recv/2來產生ECONNRESET
  2. Mac OS X和Linux在這里的行為是否有所不同?

在某些情況下可能會發生這種情況。

嘗試在套接字上發送新數據,該套接字中的遠程端點已開始關閉它的連接結束,這可能會導致ECONNRESET。 (有時可能會導致SIGPIPE升高)。

通常,這很難重現,因為大多數套接字代碼都是通過檢測返回0的recv()調用來通知關閉的連接。

如果遠程主機崩潰或斷電,也會發生這種情況。 典型的場景是兩台主機之間相互具有活動的TCP連接。 兩個主機都沒有使用TCP保持活動,並且僅在彼此之間定期發送/接收數據。 目前,假設兩個主機都處於空閑狀態,並且彼此之間沒有任何數據可發送。

第一台主機HOST A暫時停電(即拔下電源線)並重新啟動。 另一台主機HOST B不了解中斷情況。 這樣,TCP狀態機認為套接字仍處於連接狀態。 在某個時候,主機B嘗試在套接字上發送數據。 IP數據包最終到達主機A。但是,自重啟以來,主機A的TCP狀態機沒有主機B的IP:端口的連接記錄。 因此,它唯一能做的就是發回RST通知HOST B,該連接已死。

我聽說過,但是我可能是錯的...通過使用具有零值的SO_LINGER可以將套接字強制為CLOSED狀態而不發送FIN。 因此,另一端發送的后續數據將以RST作為響應。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM