OTP behavior for writing non-blocking servers
Switch branches/tags
Nothing to show
Clone or download
Pull request Compare This branch is 3 commits ahead, 10 commits behind kevsmith:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



gen_nb_server is an OTP behavior designed to simplify writing completely non-blocking TCP servers. Gone are the days of having to use a separate process to perform the listen/accept loop. Instead, gen_nb_server uses features built into prim_inet to create a truly non-blocking server. This is the same mechanism networking-intense projects, like RabbitMQ, use to create their TCP servers.

In addition, every gen_nb_server is also a gen_server so you can gen_server:call/cast/info to your heart's content! What's not to like!?!

Coming soon:

  • Ability to dynamically add/remove listen ports
  • Possibily automate the creation of per-connection worker processes

How to use gen_nb_server

  1. Drop the gen_nb_server behavior annotation at the top of your source file like so:
  1. Implement the required functions. These include the usual suspects from gen_server (see the gen_server manpage for details) and two new functions: sock_opts/0 and new_connection/2.

2a. sock_opts/0 is used by gen_nb_server to retrieve the set of socket options to use when creating the listen socket. These options will also be inherited by the client connection sockets. See the manpages for gen_tcp and inet for more information on socket options.

2b. new_connection/2 is called every time a new connection is accepted. It is called with the newly connected socket and the server's current state.

Here's a complete example which should give you an idea on how to use gen_nb_server:



-export([init/1, handle_call/3, handle_cast/2, handle_info/2]).
-export([terminate/2, sock_opts/0, new_connection/2]).


start_link(IpAddr, Port) ->
  gen_nb_server:start_link(?MODULE, IpAddr, Port, []).

init([]) ->
  {ok, []}.

handle_call(_Msg, _From, State) ->
  {reply, ignored, State}.

handle_cast(_Msg, State) ->
  {noreply, State}.

handle_info(_Msg, State) ->
  {noreply, State}.

terminate(_Reason, _State) ->

sock_opts() ->
  [binary, {active, once}, {packet, 0}].

new_connection(Sock, State) ->
  gen_tcp:send(Sock, list_to_binary(io_lib:format("No soup for you!~n", []))),
  {ok, State}.

Note: This code is also available in priv/example.