[erlang-questions] Re: what about little-endians?

Camilo Cerchiari <>
Mon Mar 15 16:21:03 CET 2010


thank you all for your comments.


On Fri, Mar 12, 2010 at 22:56, Edwin <> wrote:

> It's not actually that difficult to decode it yourself. Switch to
> {active, false} and spawn a process to extract messages from the TCP
> stream using gen_tcp:read/2,3 and send them to your gen_fsm/
> gen_server.
>
> Here's something to start you off. It does work, but I'm sure there
> may be bugs so no guarantees and I am certain someone else could write
> it better than this.
>
> -module(demux).
> -behaviour(gen_server).
>
> %% API
> -export([start/2, start_link/1, start_link/2, stop/1]).
>
> %% gen_server callbacks
> -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
>     terminate/2, code_change/3]).
>
> -export([wait_recv/3, recv_loop/3]).
>
> -define(SERVER, ?MODULE).
>
> -record(state, {
>        host,
>        port,
>        recv_pid,
>        socket
>    }).
>
> %%====================================================================
> %% API
> %%====================================================================
> start(Host, Port) when is_integer(Port) ->
>    gen_server:start(?MODULE, [Host, Port], []).
>
> start_link(Host, Port) when is_integer(Port) ->
>    gen_server:start_link(?MODULE, [Host, Port], []).
>
> start_link([Host, Port]) when is_list(Port) ->
>    NPort = list_to_integer(Port),
>    gen_server:start_link(?MODULE, [Host, NPort], []).
>
> stop(ServerRef) ->
>    gen_server:cast(ServerRef, stop).
>
> %%====================================================================
> %% gen_server callbacks
> %%====================================================================
>
> % Connect to host:port and wait for it to send stuff
> init([Host, Port]) ->
>    {ok, Sock} = gen_tcp:connect(Host, Port, [binary, {packet, 0},
> {active, false}]),
>    Self = self(),
>    Pid = spawn_link(fun() -> wait_recv(Self, Sock, <<>>) end),
>    {ok, #state{host = Host, port = Port, recv_pid = Pid, socket =
> Sock}}.
>
> handle_call(_Request, _From, State) ->
>    {reply, {error, invalid_request}, State}.
>
> handle_cast(stop, State) ->
>    (catch gen_tcp:close(State#state.socket)),
>    {stop, normal, State};
> handle_cast(_Msg, State) ->
>    {noreply, State}.
>
> handle_info({tcp_packet, Packet}, State) ->
>    io:format("Got a packet: ~p~n", [Packet]),
>    % Do something with packet
>    {noreply, State};
> handle_info({recv_error, {_Error, _Socket} = Err}, State) ->
>    io:format("Got a receive error: ~p~n", [Err]),
>    {stop, Err, State};
> handle_info(_Info, State) ->
>    {noreply, State}.
>
> terminate(_Reason, State) ->
>    io:format("Closing socket~n"),
>    (catch gen_tcp:close(State#state.socket)),
>    ok.
>
> code_change(_OldVsn, State, _Extra) ->
>    {ok, State}.
>
> %%--------------------------------------------------------------------
> %% Internal
> %%--------------------------------------------------------------------
> wait_recv(SvrRef, Socket, Buffer) ->
>    case gen_tcp:recv(Socket, 0) of
>        {ok, Input} ->
>            io:format("wait_recv: got ~p~n", [Input]),
>            B = handle_input(SvrRef, <<Buffer/bytes, Input/bytes>>),
>            ?MODULE:recv_loop(SvrRef, Socket, B);
>        Error ->
>            SvrRef ! {recv_error, {Error, Socket}}
>    end.
>
> recv_loop(SvrRef, Socket, Buffer) ->
>    case gen_tcp:recv(Socket, 0, 0) of
>        {ok, Input} ->                    % Some input waiting
> already
>            io:format("recv_loop: got ~p~n", [Input]),
>            B = handle_input(SvrRef, <<Buffer/bytes, Input/bytes>>),
>            ?MODULE:recv_loop(SvrRef, Socket, B);
>        {error, timeout} ->               % No more socket data
> immediately available
>            B = handle_input(SvrRef, Buffer),
>            ?MODULE:wait_recv(SvrRef, Socket, B);
>        Error ->
>            SvrRef ! {recv_error, {Error, Socket}}
>    end.
>
> handle_input(SvrRef, <<Length:32/little-integer, Data/bytes>>) ->
>    case Data of
>        <<Packet:Length/bytes, Rest/bytes>> ->
>            io:format("Sending tcp_packet to ~p: ~p~n", [SvrRef,
> Packet]),
>            SvrRef ! {tcp_packet, Packet},
>            handle_input(SvrRef, Rest);
>        TooShort ->
>            TooShort
>    end;
>
> handle_input(_SvrRef, <<_Data/bytes>> = B) ->
>    B.
>
> To test it, run it in one Erlang node, and run this small test program
> in another:
>
> -module(demux_test).
> -compile([export_all]).
>
> go(Port) when is_integer(Port) ->
>    Opts = [binary, {packet, 0}],
>    {ok, LSock} = gen_tcp:listen(Port, Opts),
>    {ok, Sock} = gen_tcp:accept(LSock),
>    Msg = <<"Hello, sock.\n">>,
>    send_msg(Sock, Msg, 100).
>
> send_msg(Sock, Msg, Count) when Count > 0 ->
>    lists:foreach(
>        fun(X) ->
>                N = integer_to_list(X),
>                NumberedMsg = list_to_binary([N, $:, Msg]),
>                Len = byte_size(NumberedMsg),
>                gen_tcp:send(Sock, <<Len:32/integer-little,
> NumberedMsg/bytes>>)
>        end,
>        lists:seq(1, Count)
>    ).
>
> Hope this helps.
>
> On Mar 12, 2:45 pm, Camilo Cerchiari <>
> wrote:
> > i'm ok with writing it just for myself, if it would be so.
> > some advice to get started with the code is then what i'm looking for.
> > where should i start?
> >
> >
> >
> > On Fri, Mar 12, 2010 at 17:20, Max Lapshin <>
> wrote:
> > > I think, you will be refused for this feature, because big-endian is
> > > standard for network transmission.
> > > In this case you will have to write your own buffered demuxer.
>
> ________________________________________________________________
> erlang-questions (at) erlang.org mailing list.
> See http://www.erlang.org/faq.html
> To unsubscribe; mailto:
>
>


More information about the erlang-questions mailing list