Erlang get_tcp:recv data length

Vance Shipley vances@REDACTED
Thu Mar 3 18:28:07 CET 2011


Below is an example snipped from some code I use where the protocol
on a TCP connection is ASCII line based with the Start-of-Transmission
(STX) and End-of-Transmission (ETX) ASCII characters use to delinetated
each "frame".  In simple cases one frame (STX.......ETX) is received in
one message.  However when there are multiple messages sent quickly they
could wind up in the same TCP packet.  It could also be that with slow 
charater based writes one frame is received in multiple TCP packets.

The code below is meant to buffer up the incoming feed and act only
when a complete frame is received.


    -behaviour(gen_server).
    
    -define(STX, 2).
    -define(ETX, 3).
    
    handle_info({tcp, Socket, Data}, #state{socket = Socket} = State) ->
       handle_frame(Data, State);
    
    %% Parse the receive buffer for a framed record.
    %%
    handle_frame([?STX | Rest] = Data, State) ->
       case lists:splitwith(fun(?ETX) -> false; (_) -> true end, Rest) of
          {Record, [?ETX]} ->
                   % handle received frame
                   ...
                   NewState = State#state{buffer = []},
                   {noreply, NewState};
          {Record, [?ETX, ?STX | T]} ->
                   % handle received frame
                   ...
                   NewState = State#state{buffer = []},
                   handle_frame([?STX | T], NewState);
          {_, []} ->
             NewState = State#state{buffer = Data},
             {noreply, NewState}
       end;
    handle_frame([], State) ->
       {noreply, State};
    handle_frame(Data, #state{buffer = [?STX | _]} = State) ->
       handle_frame(State#state.buffer ++ Data, State#state{buffer = []});
    handle_frame([_ | T] = Data, #state{buffer = []} = State) ->
       handle_frame(T, State).

-- 
   -Vance


More information about the erlang-questions mailing list