[erlang-questions] how to use sockets in erlang

Jesper Louis Andersen jesper.louis.andersen@REDACTED
Fri Jun 17 13:32:02 CEST 2011


On Fri, Jun 17, 2011 at 13:10, Ivan Uemlianin <ivan@REDACTED> wrote:

I am just shooting in the dark here, but I have a guess at what is wrong:

> Python version --- works:
>
>    jsondata = json.dumps(data) + "\n"
>    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>    s.connect((appliance_host, appliance_port))
>    s.send(jsondata)
>    returndata = s.recv(4096)

The Python recv semantics follow that of the unix kernels recv(2)
call. I.e., the 4096 is a buffer and you will get at most 4096 bytes,
or less than that.

> Erlang version --- doesn't work:
>
>    JsonData = list_to_binary(mochijson2:encode(Data) ++ <<10>>),

You usually don't have to call list_to_binary/1 here. The value
[mochijson2:encode(Data), <<10>>] is an iolist() and sockets take
iolist() types. That way, you won't be creating new binaries but just
refer to already existing binaries in lists. It is much faster than
building the binary first and then shoving it out the socket. It is a
common idiom to make Erlang go fast when rendering data structures to
output. Look up iolist()s. They are a key element to make your code go
fast as it avoids a large number of binary constructions.

>    {ok, Socket} = gen_tcp:connect(?APPLIANCE_HOST, ?APPLIANCE_PORT,
>                                  [inet,
>                                   binary,
>                                   {active, false},
>                                   {packet, 0}]),
>    ok = gen_tcp:send(Socket, JsonData),
>    Result = gen_tcp:recv(Socket, 4096, 5000),

The Erlang semantics here are different. You are blocking until you
have exactly 4096 bytes of data. If less is received, you will get
{error, closed} back, or a timeout after 5000 ms. You should be
calling gen_tcp:recv(Socket, 0, 5000) and then use byte_size(X) on the
result yourself. It also means you will have to drain the socket
yourself in a separate function. The solution is to figure out what
the stream-semantics and syntax is and handle that with a couple of
Erlang functions.

Another important thing to look out for is that in Erlang the Socket
is a port() bound to the connecting process (by default -- the
controlling process can change with the controlling_process call). If
the bound process dies, the socket closes. As soon as you begin
passing sockets between processes this will haunt you unless you are
aware of it. The cool thing about it as that you get automatic
"resource reclamation" because of this. It also happens with files
(they are closed), ETS tables, and so on.


-- 
J.



More information about the erlang-questions mailing list