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

Garret Smith <>
Wed Apr 9 01:25:23 CEST 2014


Basically, this has everything to do with TCP sockets (and the OS
implementation) and very little to do with Erlang.  I do get {error,
closed} from gen_tcp:send when the client disconnects.  I'm running
R16B03-1 on FreeBSD 10.

Here are some decent descriptions of the problem:

http://www.linuxquestions.org/questions/programming-9/how-could-server-detect-closed-client-socket-using-tcp-and-c-824615/

The second answer in the page above has some good links too, pulled out for
easy reference:

http://stackoverflow.com/questions/722240/instantly-detect-client-disconnection-from-server-socket
http://www.softlab.ntua.gr/facilities/documentation/unix/unix-socket-faq/unix-socket-faq-2.html#ss2.8

-Garret


On Tue, Apr 8, 2014 at 1:40 PM, Fred Hebert <> wrote:

> 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.
> _______________________________________________
> erlang-questions mailing list
> 
> http://erlang.org/mailman/listinfo/erlang-questions
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20140408/c35dca35/attachment.html>


More information about the erlang-questions mailing list