November 22th Sunday

Erlang sockets

 

  Erlang sockets can be opened in one of three modes: active, active once, or passive. This is done by including an option {active, true | false | once} in the Options argument to either gen_tcp:connect(Address, Port, Options) or gen_tcp:listen(Port, Options).

 

  If {active, true} is specified, then an active socket will be created; {active false} specifies a passive socket. {active, once} creates a socket that is active but only for the reception on one message; after it has received this message, it must be reenabled before it can receive the next message.

 

  The difference between an active and passive socket has to do withwhat happens when messages are received by the socket.

 

  •   Once an active socket has been created, the controlling process will be sent {tcp, Socket, Data} messages as data is received. There is no way the controlling process can control the flow of these messages. A rogue client could send thousands of messages to the system, and these would all be sent to the controlling process. The controlling process cannot stop this flow of messages.

 

  •   If the socket was opened in passive mode, then the controlling process has to call gen_tcp:recv(Socket, N) to receive data from the socket. It will then try to receive exactly N bytes from the socket. If N = 0, then all available bytes are returned. In this case, the server can control the flow of messages from the client by choosing when to call gen_tcp:recv.

 

Active Message Reception (Nonblocking)

 

{ok, Listen} = gen_tcp:listen(Port, [..,{active, true}...]),
{ok, Socket} = gen_tcp:accept(Listen),
loop(Socket).

 

loop(Socket) ->
  receive
    {tcp, Socket, Data} ->
      ... do something with the data ...
    {tcp_closed, Socket} ->
      ...
  end.

This process cannot control the flow of messages to the server loop. If the client produces data faster than the server can consume this data, then the system can be flooded with messages—the message buffers will fill up, and the system might crash or behave strangely. This type of server is called a nonblocking server because it cannot block the client. We should write a nonblocking server only if we can convince ourselves that it can keep up with the demands of the clients.

 

Passive Message Reception (Blocking)

 

  The server opens the socket in passive mode by setting the {active, false} option. This server cannot be crashed by an overactive client that tries to flood it with too much data.


The code in the server loop calls gen_tcp:recv every time it wants to receive data. The client will block until the server has called recv. Note that the OS does some buffering that allows the client to send a small amount of data before it blocks even if recv has not been called.

 

{ok, Listen} = gen_tcp:listen(Port, [..,{active, false}...]),
{ok, Socket} = gen_tcp:accept(Listen),
loop(Socket).


loop(Socket) ->
  case gen_tcp:recv(Socket, N) of
    {ok, B} ->
      ... do something with the data ...
      loop(Socket);
    {error, closed}
      ...
  end.

 

The Hybrid Approach (Partial Blocking)

 

  You might think that using passive mode for all servers is the correct approach. Unfortunately, when we’re in passive mode, we can wait for the data from only one socket. This is useless for writing servers that must wait for data from multiple sockets.

 

  Fortunately, we can adopt a hybrid approach, neither blocking nor nonblocking. We open the socket with the option {active, once}. In this mode, the socket is active but for only one message. After the controlling processes has been sent a message, it must explicitly call inet:setopts to reenable reception of the next message. The system will block until this
happens. This is the best of both worlds. Here’s what the code looks like:

 

{ok, Listen} = gen_tcp:listen(Port, [..,{active, once}...]),
{ok, Socket} = gen_tcp:accept(Listen),
loop(Socket).


loop(Socket) ->
    receive
      {tcp, Socket, Data} ->
        ... do something with the data ...
        %% when you're ready enable the next message
        inet:setopts(Sock, [{active, once}]),
        loop(Socket);
      {tcp_closed, Socket} ->
        ...
    end.

 

Using the {active, once} option, the user can implement advanced forms of flow control (sometimes called traffic shaping) and thus prevent a server from being flooded by excessive messages. 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值