• Stars
    star
    133
  • Rank 272,600 (Top 6 %)
  • Language
    Erlang
  • Created about 15 years ago
  • Updated over 13 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

OTP behavior for writing non-blocking servers

Description

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?

How to use gen_nb_server

  1. Drop the gen_nb_server behavior annotation at the top of your source file like so:
-behavior(gen_nb_server).
  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/4.

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/4 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:

-module(example).

-export([start_link/0,
         add_listener/3,
         remove_listener/3]).

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

-behavior(gen_nb_server).

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

add_listener(Pid, IpAddr, Port) ->
    gen_server:call(Pid, {add_listener, IpAddr, Port}).

remove_listener(Pid, IpAddr, Port) ->
    gen_server:call(Pid, {remove_listener, IpAddr, Port}).

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

handle_call({add_listener, IpAddr, Port}, _From, State) ->
    case gen_nb_server:add_listen_socket({IpAddr, Port}, State) of
        {ok, State1} ->
            {reply, ok, State1};
        Error ->
            {reply, Error, State}
    end;
handle_call({remove_listener, IpAddr, Port}, _From, State) ->
    case gen_nb_server:remove_listen_socket({IpAddr, Port}, State) of
        {ok, State1} ->
            {reply, ok, State1};
        Error ->
            {reply, Error, State}
    end;
handle_call(_Msg, _From, State) ->
    {reply, ignored, State}.

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

handle_info({tcp, Sock, Data}, State) ->
    Me = self(),
    P = spawn(fun() -> worker(Me, Sock, Data) end),
    gen_tcp:controlling_process(Sock, P),
    {noreply, State};

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

terminate(_Reason, _State) ->
    ok.

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

new_connection(_IpAddr, _Port, Sock, State) ->
    Me = self(),
    P = spawn(fun() -> worker(Me, Sock) end),
    gen_tcp:controlling_process(Sock, P),
    {ok, State}.

worker(Owner, Sock) ->
    gen_tcp:send(Sock, "Hello\n"),
    inet:setopts(Sock, [{active, once}]),
    gen_tcp:controlling_process(Sock, Owner).

worker(Owner, Sock, Data) ->
    gen_tcp:send(Sock, Data),
    inet:setopts(Sock, [{active, once}]),
    gen_tcp:controlling_process(Sock, Owner).

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

More Repositories

1

pteracuda

Framework for using CUDA from Erlang
C++
111
star
2

herml

Erlang port of Haml
Erlang
51
star
3

giza

Erlang client for the Sphinx search engine
Erlang
34
star
4

gen_paxos2

Snapshot of the gen_paxos repo (now missing)
Erlang
30
star
5

basic_erl_driver

Basic linked-in Erlang driver
C
28
star
6

reddy

Exploring writing a redis client in Erlang
Erlang
20
star
7

membox

Redis-like storage server written in Erlang
Erlang
15
star
8

carrot

REST management interface for RabbitMQ
Erlang
13
star
9

erlz

Erlang wrapper for the fastlz (LZO-like) data compression library
C
12
star
10

baberl

Erlang interface to libiconv
Erlang
11
star
11

erlang_cli

Starting & configuring distributed Erlang for escript
Erlang
9
star
12

hl-emacs

My Emacs Config (Erlang and misc. goodness)
Emacs Lisp
9
star
13

crest

(Concurrency | coordination) + REST
Erlang
8
star
14

hammy

Erlang bindings for HamsterDB
C
8
star
15

erlang_factory

Code & Slides For Erlang Factory
Erlang
7
star
16

rebar-templates

Templates for common usage scenarios
Erlang
6
star
17

emacs

My modular Emacs config
Emacs Lisp
5
star
18

brine

Erlang NIF for ed25519 key generation, message signing, signature verification, and key pair serialization.
C
5
star
19

readme

My management style README
4
star
20

erlang_js-jaegermonkey

Porting erlang_js to use jaegermonkey
Erlang
4
star
21

hjalp

Embed edoc descriptions and type specs into compiled beam files
Erlang
3
star
22

ulib

C
3
star
23

doku

Literate programming tool inspired by docco and marginalia
Erlang
3
star
24

libbrine

ed25519 key generation, message signing, and signature verification
C
3
star
25

kirby

Experiment in fast unstructured BLOB storage
Erlang
2
star
26

erleveldb

Erlang LevelDB Driver
C++
2
star
27

quadtreex

Pure Elixir quadtree
Elixir
2
star
28

cog_slack

Elixir
1
star
29

cog_hipchat

Elixir
1
star
30

behavex

Pure Elixir behavior tree
Elixir
1
star
31

lifx_protocol

LIFX's LAN protocol implementation
Elixir
1
star
32

town

Small town simulator
1
star
33

ejson

C
1
star