• erlang R17新socket选项{active,N}


    erlang R17带来了新的socket选项{active,N} 。与{active,once}连同应用层提供的流量控制。为什么会这样选择,{active,once}不能够有效地抑制了很多socket消息做?

    我们知道,,{active,once}一次设置active选项,才干继续接收erlang的消息通知。实际上。每次设定{active,once}都意味着调用一次epoll_ctl, 假设请求过于频繁,就会有大量的epoll_ctl调用。erlang眼下仅仅有一个线程会收割epoll_wait事件。epoll_wait要轮询已经就绪的ctl队列。假设大量的ctl事件将会堵塞了epoll_wait的操作,造成网络处理能力的下降。

    那么。我们能不能设定接收N个的socket消息后再运行一次epoll_ctl。这样能够有效降低epoll_ctl的调用。{active,N}就是这样出现的。

    以下来看一下{active,N}的说明

    Add the {active,N} socket option for TCP, UDP, and SCTP,where N is an integer in the range -32768..32767, to allow a caller to specify the number of data messages to be delivered to the controlling process. Once the socket's delivered message count either reaches 0 or is explicitly set to 0 with inet:setopts/2 or by including {active,0} as an option when the socket is created, the socket transitions to passive({active, false}) mode and the socket's controlling process receives a message to inform it of the transition. TCP sockets receive {tcp_passive,Socket}, UDP sockets receive {udp_passive,Socket} and SCTP sockets receive {sctp_passive,Socket}. 

    The socket's delivered message counter defaults to 0, but it can be set using {active,N} via any gen_tcp, gen_udp, or gen_sctp function that takes socket options as arguments, or via inet:setopts/2. New N values are added to the socket's current counter value, and negative numbers can be used to reduce the counter value. Specifying a number that would cause the socket's counter value to go above 32767 causes an einval error. If a negative number is specified such that the counter value would become negative, the socket's counter value is set to 0 and the socket transitions to passive mode. If the counter value is already 0 and inet:setopts(Socket, [{active,0}]) is specified, the counter value remains at 0 but the appropriate passive mode transition message is generated for the socket.

    设定了{active,N}选项后,进程在接收了N个包后,会收到{tcp_passive, Socket}消息,意味着这个Socket进入被动模式,须要又一次设置active选项。

    接下来。在实际的样例中測试这个參数:

    -module(server).
    
    -export([start/0]).
    -export([continue/1]).
    -define( PORT, 8888).
    
    start() ->
      {ok, LSock} = gen_tcp:listen(?PORT, [binary, {packet, 0},{active, false}]),
      io:format("socket listen: ~p on ~p ~n",[LSock, ?

    PORT]), accept(LSock). accept(LSock) -> {ok, ASock} = gen_tcp:accept(LSock), Pid = spawn(fun() -> do_loop(ASock) end), gen_tcp:controlling_process(ASock, Pid), inet:setopts(ASock, [{active, 3}]), accept(LSock). do_loop(ASock) -> receive {tcp, Socket, Data} -> io:format("socket ~p recv: ~p ~n",[Socket, Data]); {tcp_closed, Socket} -> io:format("socket ~p close ~n",[Socket]); {tcp_passive,Socket} -> io:format("socket ~p is passive, please call continue/1 ~p ~n",[Socket, self()]); release_passive -> inet:setopts(ASock, [{active, 3}]); Err -> io:format("socket may error: ~p ~n",[Err]) end, do_loop(ASock). continue(Pid) -> Pid ! release_passive, ok.

    编译启动这个模块后。我们创建一个client来请求这个服务端:

    1> f(S), {ok,S} = gen_tcp:connect({127,0,0,1},8888,[{packet,0}]).
    {ok,#Port<0.526>}
    2> gen_tcp:send(S,<<"hello">>).
    ok
    3> gen_tcp:send(S,<<"hello">>).
    ok
    4> gen_tcp:send(S,<<"hello">>).
    ok
    5> gen_tcp:send(S,<<"hello">>).
    ok
    服务端控制台打印了这种信息:

    D:	mp>erl -s server
    socket listen: #Port<0.422> on 8888
    Eshell V6.0  (abort with ^G)
    1> socket #Port<0.479> recv: <<"hello">>
    1> socket #Port<0.479> recv: <<"hello">>
    1> socket #Port<0.479> recv: <<"hello">>
    1> socket #Port<0.479> is passive, please call continue/1 <0.33.0>
    1> server:continue(pid(0,33,0)).
    socket #Port<0.479> recv: <<"hello">>
    ok
    2>
    在上面的样例中,我们设定了{active,3}的选项,在接收到client3次数据后,socket进入了passive状态,在又一次设置{active,N}后继续接收tcp消息。

    那么,怎样在实际项目中运用{active,N}选项?

    inet:setopts(Socket, [{active, 300}]),
    erlang:send_after(30 * 1000, self(), release_passive);
    大概思路是,在30秒内最多接收300个包。超过就不接收,等待这30秒完毕后继续接收。如此重复。

    利用这点还能够加多一个计数器,假设超过10次进入passive状态,说明这个Socket存在问题,有攻击的行为。


    參考:

    http://blog.csdn.net/mycwq/article/details/24814843
    http://www.erlang.org/download/otp_src_17.0.readme
    http://blog.yufeng.info/archives/2970

  • 相关阅读:
    十年经验手把手教你选购翡翠
    眼睛视力
    玻璃
    前端小技巧
    儿童牙齿矫正
    MySQL的JDBC驱动源码解析
    书海杂谈
    电子设备
    股市国家队
    影视
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4601853.html
Copyright © 2020-2023  润新知