Erlang inet:setopts

setopts(Socket, Options) -> ok | {error,posix()}

Types:

Socket = socket()
Options = [socket_setopt()]
socket_setopt() = gen_sctp:option()
| gen_tcp:option()
| gen_udp:option()

Sets one or more options for a socket. The following options are available:

{active, true | false | once}

If the value is true, which is the default, everything received from the socket will be sent as messages to the receiving process. If the value isfalse (passive mode), the process must explicitly receive incoming data by callinggen_tcp:recv/2,3 or gen_udp:recv/2,3 (depending on the type of socket).

If the value is once ({active, once}),one data message from the socket will be sent to the process. To receive one more message,setopts/2 must be called again with the {active, once} option.

When using {active, once}, the socket changes behaviour automatically when data is received. This can sometimes be confusing in combination with connection oriented sockets (i.e.gen_tcp) as a socket with{active, false} behaviour reports closing differently than a socket with{active, true} behaviour. To make programming easier, a socket where the peer closed and this was detected while in{active, false} mode, will still generate the message {tcp_closed,Socket} when set to{active, once} or{active, true} mode. It is therefore safe to assume that the message{tcp_closed,Socket}, possibly followed by socket port termination (depending on theexit_on_close option) will eventually appear when a socket changes back and forth between{active, true} and{active, false} mode. However,when peer closing is detected is all up to the underlying TCP/IP stack and protocol.

Note that {active,true} mode provides no flow control; a fast sender could easily overflow the receiver with incoming messages. Use active mode only if your high-level protocol provides its own flow control (for instance, acknowledging received messages) or the amount of data exchanged is small. {active,false} mode or use of the {active, once} mode provides flow control; the other side will not be able send faster than the receiver can read.

erlang推荐用{active,once}模式,无需争议的。

1.主动模式

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

逻辑处理  //在正常情况下,没啥问题,但是如果我们的服务面对互联网就有很大的风险,如果遭受攻击的时候,对端发送大量的数据包的时候,我们的系统就会异步收到大量的消息,可能会超过我们的进程处理能力。最要命的是,我们无法让包停止下来,最后的结局就是我们的服务器因为缺少内存crash了。

     {tcp_closed,Socket} -> ... 
 end.

2.被动模式

{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} -> 

... 数据处理 ... //调用recv收数据,recv是阻塞的,等待driver返回消息

loop(Socket); 
    {error,closed} ... 
 end.

3.混合模式

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

 ... 数据处理 ... %%调用 inet:setopts之前是阻塞的,非gen_tcp:recv的阻塞

%%准备好启用下一条消息时 
         inet:setopts(Socket,[{active,once}]),
           loop(Socket);
     {tcp_closed,Socket} -> ... 

R15B02对active once进行了优化,降低延迟,最大吞吐量提高4~6倍!

你可能感兴趣的:(erlang)