[erlang-questions] using a socket to send and receive

Essien Essien <>
Thu Aug 19 14:53:03 CEST 2010


HI Roberto,

On Thu, Aug 19, 2010 at 12:24 PM, Roberto Ostinelli <> wrote:
> dear list,
>
> i need to use a socket both to receive and send data. the socket must
> be listening for incoming data from TCP, but it needs also to receive
> data to be sent from external processes when events occur. the socket
> is in raw mode.
>
> i'm using a binary protocol which specifies that the length of the
> incoming data varies continuously.
>
> my current solution is to use 2 processes, one to listen for incoming
> data in passive mode, the other to listen for incoming erlang messages
> from other processes, in a simple way as:
>
> recv(Sock, Len) ->
>        case gen_tpc:recv(Sock, Len) of
>                [...]
>        end.
>
> send(Sock) ->
>        receive
>                {send, DataToSend} -> gen_tpc:send(Sock, DataToSend)
>        end.
>
> i use passive mode since it is very simple to set the length of the
> incoming data to wait for with gen_tpc:recv/2.
>
> what i would like to do is to use a single process in {active, once}
> mode, so that both messages received from the socket AND from the
> external processes are treated within a same loop.
>
> the solution would look something like:
>
> sock_loop(Sock, Len) ->
>        inet:setopts(Sock, [{active, once}, {recv_size, Len}]),
>        receive
>                {http, Sock, Data} ->
>                        % data received from TCP socket, do something with it
>                        [...];
>                {send, DataToSend} ->
>                        % data received from external processes, send it to socket
>                        gen_tpc:send(Sock, DataToSend)
>        end.
>
> problem is that the option 'recv_size' that i've specified here above
> obviously does not exist, and i can't find how to set the length of
> the packet to receive in the way that i can easily do with passive
> mode and gen_tpc:recv/2. the sndbuf inet option does not seem to be
> it, since it's a buffer size.
>
> i've read the docs but i guess i have missed a point somewhere.
>
> can anyone point me out on how to do this?

I've encountered this before where my process recieves a binary PDU
stream from a server, but needs to break them up and unpack them
properly before delivering to another process to deal with them.

My approach is still to use {active, once}, thus recieving _all_
available data. When I process though, I only take the lenght of data
that I need and leave the Rest in a loop variable. The next time
around, I prepend the Rest from the previous run to the new coming
data, then recurse. So, something like this:

% I'm assuming that the socket is delivering
% binary not list data.
sock_loop(Sock, Len, Rest0) ->
       inet:setopts(Sock, [{active, once}]),
       receive
               {http, Sock, Data0} ->
                        % data received from TCP socket, do something with it
                        % first prepend pending data in Rest0 before continuing
                        Data1 = list_to_binary([Rest0, Data0]),
                        <<Data:Len,Rest1/binary>> = Data1,

                         % Now you can do what you want with Data
                          worker_proc ! <<Data:Len>>,
                           sock_loop(Sock, Len, Rest1);
               {send, DataToSend} ->
                       % data received from external processes, send
it to socket
                       gen_tpc:send(Sock, DataToSend)
       end.


This does not exactly give you a way to modify the receive buffer, but
still allows you to achieve what you need to.

cheers,
Essien
>
> thank you,
>
> r.
>
> ________________________________________________________________
> 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