[erlang-questions] tcp data in a gen_fsm

Jachym Holecek freza@REDACTED
Sun Nov 29 16:09:12 CET 2015

# Frans Schneider 2015-11-29:
> I have a gen_fsm representing the tcp connection to a remote server
> with 6 states defined. Tcp data is handled by handle_info with
> active = once.Tcp packets can contain more than one commands/data
> items.
> [...]

If your handle_info() were dealing with one PDU at a time, it's fine
to do something like:

    handle_info({tcp, Sock, Data}, State_name, #state{...} = State) ->
        ?MODULE:State_name(Event, State);

Probably not a coincidence that most of the gen_fsm callbacks have the
same return convention, allows you to seamlessly transfer control like

If you find yourself wanting to perform more than one state transition
per incoming event, that probably speaks of poorly structured solution.

> I can of course use a seperate process for handling the tcp stuff
> which makes the gen_fsm calls, but was just wondering if this could
> work as well.

You're better off spawning a utility process below you FSM, giving it
ownership of the socket, then letting it do the reception and framing,
sending events to the parent process via send_event(). This utility
process should end up really simple and mostly stateless, you probably
want plain proc_lib:spawn_link(), keeping the code for it in the same
module as the FSM.

You'll probably want at least a primitive form of flow control between
the child and the parent, for safety, but that's easy (we can get back
to that later if you like).

Don't know the details of what you're doing, but a generic protocol
stacks comment: your receiving process has to handle the full inbound
signalling frequency, which makes it a precious shared resource. It
should thus do as little work as possible -- with sanely designed
protocols this means it would look at constant-size packet header,
figure out what to do, and let somebody else decode the payload and
perform business logic (or complicated administrative tasks internal
to the stack itself). Usually the real work ends up in temporary
worker processes (one per request, or one per session if the protocol
has such notion, or whatever else makes sense in your context).

This maximazes the signalling frequency you can handle, at the same
time it helps you spread load across all available cores, also there's
the fault isolation angle.

	-- Jachym

More information about the erlang-questions mailing list