[erlang-questions] Writing gen_servers with TCP listeners

Dave Peticolas dave@REDACTED
Mon May 12 00:48:32 CEST 2008


Eric Maland wrote:
> Hello,
> 
> I am having some trouble writing a gen_server that is a tcp listener  
> that works outside the shell.
> 
> My goal has been to write a gen_server that starts listening on a  
> socket and manages a connection pool of accept()-ors.  This seems like  
> a pretty standard behaviour and is very easy to implement, but every  
> implementation I've produced runs perfectly in the shell but not in an  
> erl instance without a shell.
> 
> This sort of problem seems to be referenced in a previous thread (http://www.erlang.org/pipermail/erlang-questions/2008-January/032400.html 
>   ), but I have found 0 examples of how to apply the information there  
> to a gen_server - clearly the server needs to live forever, but how do  
> you get a gen_server to hang around?  Is it acceptable to implement a  
> handle_call() that just does a receive after infinity -> foo end ???   
> Who would call that?  I have tried that, and it seemed like after 10  
> or so requests the server died (presumably on some timeout from the  
> supervisor insantiating it??).
> 
> I found a great example of a gen_server tcp listener at http://www.duomark.com/erlang/tutorials/proxy.html 
>    but this also exhibits the same problem outside the shell - it  
> serves one request and then the socket is closed.
> 
> Does anyone have or know of a great tcp listener example that works  
> outside the shell (eg started with: 'erl -boot start_sasl -s mymodule  
> start'), or another interesting way to resolve this, specifically when  
> writing  gen_server?
> 
> Here are some models I have gone through, all of which work in the  
> shell but not outside the shell:
> 
> gen_server:init listen()'s ->
>    spawn()'s a connection pool ->
>      each pool process accept()'s and spawns another pool process
> 
> In the shell: works fine
> Outside the shell: 2nd and subsequent accept() fails
> 
> gen_server:init listen()'s ->
>    gen_server:init calls gen_server:cast(accept_loop) ->
>      accept_loop loops forever, spawning handlers on each request (and  
> gen_tcp:controlling_process the associated connections over to the  
> processes)
> 
> In the shell: works fine
> Outside the shell: 2nd and subsequent accept() fails
> 
> These all work great in the shell but serve 1-2 requests (depending on  
> your platform) outside the shell before the socket closes.
> 
> Any advice on how to properly get the owner of the listening socket to  
> stick around in a gen_server would be appreciated.

A gen_server will 'hang around' indefinitely by design, unless you tell
it to stop or one of its callbacks fail. I don't know if this is the
problem, but you need to make sure that the listening socket itself
always has an owner too, not just the sockets created by the listening
socket.

There's an example, by Serge Aleynikov, of how to do a generic tcp
server here:

http://trapexit.org/Building_a_Non-blocking_TCP_server_using_OTP_principles

I packaged it up for erlware (http://erlware.org) and you can install it
with their 'faxien' tool, or just grab the code here:

http://git.krondo.com/?p=erlware/gen_socket.git;a=summary

dave

> Thanks!
> Eric
> 
> 
> References:
> 1. http://www.erlang.org/pipermail/erlang-questions/2008-January/032400.html
> 2. http://www.duomark.com/erlang/tutorials/proxy.html
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://www.erlang.org/mailman/listinfo/erlang-questions
> 




More information about the erlang-questions mailing list