[英]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
,这归结为两个问题:
recv/2
来产生ECONNRESET
? 在某些情况下可能会发生这种情况。
尝试在套接字上发送新数据,该套接字中的远程端点已开始关闭它的连接结束,这可能会导致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.