<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
</head>
<body text="#000000" bgcolor="#FFFFFF">
Great! thanks for your explanation. Makes sense to send messages
instead of calling the state functions.<br>
But what about style? Would you consider a solution as you describe
good style? I didn't see it in other projects used this way.<br>
<br>
(Weird thing that good style is becoming such an issue to me since I
started coding Erlang.)<br>
<br>
/Frans<br>
<br>
<div class="moz-cite-prefix">On 11/29/2015 02:59 PM, Jesper Louis
Andersen wrote:<br>
</div>
<blockquote
cite="mid:CAGrdgiXhSY-PefaNydsHYwV4WqWBVeGG23phJ1Tor1UzTfzy6w@mail.gmail.com"
type="cite">
<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 moz-do-not-send="true"
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 moz-do-not-send="true"
href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a><br>
<a moz-do-not-send="true"
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>
</blockquote>
<br>
</body>
</html>