<div dir="ltr">One possible way is to message yourself. The following needs some help because it never loops over the unpacking, which it should. But surely you get the idea. The unpack function is now tasked with returning a list of decoded packets, not just the first one:<div><br></div><div><span style="font-size:12.8px">handle_info({tcp, Socket, RawData}, State_name, #state{buffer_state = BufState} = State) -></span></div><div><span style="font-size:12.8px"> inet:setopts(Socket, [{active, once}]),</span></div><div> case unpack(BufState, RawData) of</div><div> {ok, Datas, BufState2} -></div><div> [gen_fsm:send_event(self(), {packet, D}) || D <- Datas],</div><div> {next_state, State_name, State#state { buffer_state = BufState2 }};</div><div> {more, BufState2} -></div><div> {next_state, State_name, State#state { buffer_state = BufState2 }}</div><div> end;</div><div><br></div><div>Now, you can build two variants of the unpack/2 function. Rather than returning {more, State} you can simply return {ok, [], State} which eliminates the need for a separate 'more-variant'. But some times, it is clever to return {more, NeededBytes, State} or something such in order to tell the layer how many bytes it needs before it can produce a new packet. In active mode, this allows you to expect the right number of bytes directly, which sometimes helps since you can move more or the load into the Erlang runtime.</div><div><br></div><div>Now, the beauty is that the messages will sit in your own mailbox, and in order. So you just handle them as any other messages and move the state accordingly. And when you get new stuff in, your decode it in your handle_info block and inject it into the mailbox. It is a fairly modular solution as well: you effectively decoupled the TCP state from the rest of your code, so you can now freely move it out of the FSM should you prefer doing so. Vice versa, it also decouples the protocol decoding from your FSM state, so it can worry about the semantic impact of the protocol rather than the syntactic impact.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Nov 29, 2015 at 2:27 PM, Frans Schneider <span dir="ltr"><<a href="mailto:schneider@xs4all.nl" target="_blank">schneider@xs4all.nl</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Dear list,<br>
<br>
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.<br>
I would like to feed the data into the different FSM states in the same manner as with send_event() and not handle the different states in separate handle_info clauses for the different states or a massive handle_info clause with a huge case statement.<br>
Question is, can I call the state clauses like this or do I brake OTP behavior?This is a client and blocking incoming data is not an issue.<br>
<br>
handle_info({tcp, Socket, Raw_data}, State_name, #state{buffer = Buffer} = State) -><br>
{Datas, Buffer1} = unpack(<<Buffer/binary, Raw_data/binary>>),<br>
lists:foldl(fun(Data, {StateName_in, State_in}) -><br>
{next_state, StateName_out, State_out} = ?MODULE:StateName_in({recv, Data}, State_in),<br>
{StateName_out, State_out}<br>
end, {State_name, State}, Datas),<br>
inet:setopts(Socket, [{active, once}]),<br>
{next_state, active, State#state{buffer = Buffer1}};<br>
<br>
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.<br>
<br>
Thanks,<br>
<br>
/Frans<br>
_______________________________________________<br>
erlang-questions mailing list<br>
<a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a><br>
<a href="http://erlang.org/mailman/listinfo/erlang-questions" rel="noreferrer" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature">J.</div>
</div>