[erlang-questions] Re: what about little-endians?
Camilo Cerchiari
camilo.cerchiari@REDACTED
Mon Mar 15 16:21:03 CET 2010
thank you all for your comments.
On Fri, Mar 12, 2010 at 22:56, Edwin <emofine@REDACTED> 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 <camilo.cerchi...@REDACTED>
> 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 <max.laps...@REDACTED>
> 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:erlang-questions-unsubscribe@REDACTED
>
>
More information about the erlang-questions
mailing list