[erlang-questions] Difference in 'close' for gen_tcp recv vs. active

Fred Hebert mononcqc@REDACTED
Tue Apr 8 22:40:29 CEST 2014


Hi there,

Happy fun case we're hitting on nodes using Erlang right now. We have an
HTTP proxy that does direct data streaming from a server to a client.
This is done through a series of recv from the server, and of sends to
the client. The TCP sockets involved are all in passive mode.

The problem with this approach is that because this is a purely
unidirectional stream until the server says so or the client quits, we'd
like to detect both of these events.

The server quitting or being done is easy enough, but the client
quitting cannot be detected, apparently.

It turns out that gen_tcp:send/2 always returns 'ok' even if the
connection has been closed by the peer before. Erlang/OTP just won't
acknowledge the fact unless someone tries to read from the socket,
either through gen_tcp:recv or by using inet:setopts(Port, [{active,
once}]), at which point {error, closed} starts being returned by
gen_tcp:send/2. This happens, even if `{exit_on_close, true}` is
specified as an option.

The question I have here is why is this behavior different for send than
recv. It seems that `gen_tcp:send` will happily wait for hours
pretending to send data (no matter the timeout values used are), even
once the connection has been closed by the other peer.

Is there any way for me to detect that a connection has been closed
without possibly having to poll `recv` on each packet I try to send (and
then may need to buffer all that data, which I'd prefer to avoid) or
changing the entire app's workflow to be active?

In case, here are the socket options we use:

    [{active,false},
     {broadcast,false},
     {buffer,1460},
     {delay_send,false},
     {dontroute,false},
     {exit_on_close,true},
     {header,0},
     {high_watermark,8192},
     {keepalive,false},
     {linger,{false,0}},
     {low_watermark,4096},
     {mode,binary},
     {nodelay,true},
     {packet,0},
     {packet_size,0},
     {priority,0},
     {recbuf,87380},
     {reuseaddr,true},
     {send_timeout,infinity},
     {sndbuf,65536}]

Regards,
Fred.



More information about the erlang-questions mailing list