what about little-endians?
Edwin
emofine@REDACTED
Sat Mar 13 01:56:23 CET 2010
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.
More information about the erlang-questions
mailing list