gpt4 book ai didi

erlang - gen_tcp的passive和once模式的区别

转载 作者:行者123 更新时间:2023-12-02 08:40:02 24 4
gpt4 key购买 nike

我在看 Programming Erlang 2E .在第 17 章的 Active and Passive Sockets 中,它说:

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.



相关代码:
% passive mode
loop(Socket) -> 
​case​ gen_tcp:recv(Socket, N) ​of​​ 
{ok, B} ->​ 
... do something with the data ...​ 
loop(Socket);​ 
{error, closed}​ 
...​ 
​end​.

% once mode
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​.

我看不出两者之间有什么真正的区别。 gen_tcp:recvpassive模式本质上与 receive 做同样的事情在 once模式。怎么样 once模式修复 passive的这个问题模式:

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.

最佳答案

主要区别在于您何时选择对该套接字上的事件使用react。使用主动套接字,您的进程会收到一条消息,使用被动套接字,您必须自行决定调用 gen_tcp:recv .这对你意味着什么?

编写 Erlang 程序的典型方法是让它们对事件使用react。遵循这个主题,大多数 Erlang 进程等待代表外部事件的消息,并根据它们的性质对它们使用react。当您使用事件套接字时,您能够以与其他事件完全相同的方式处理套接字数据的方式进行编程:作为 Erlang 消息。当您使用被动套接字进行编写时,您必须选择何时检查套接字以查看它是否有数据,并就何时检查 Erlang 消息做出不同的选择——换句话说,您最终不得不编写轮询例程,并且这错过了 Erlang 的大部分优势。

所以active_once之间的区别和 active ...

使用事件套接字,任何能够建立连接的外部参与者都可以用数据包轰炸进程,无论系统是否能够跟上。如果您想象一个服务器有 1000 个并发连接,其中每个数据包的接收都需要进行一些重要的计算或访问其他一些有限的外部资源(这不是一个奇怪的场景),您最终不得不选择如何处理过载。

只有 active您已经做出选择的套接字:您将让服务降级,直到事情开始失败(超时或其他情况)。

active_once sockets 你有机会做出一些选择。安 active_once socket 允许你在 socket 上接收一条消息并设置它 passive再次,直到您将其重置为 active_once .这意味着您可以编写一个阻塞/同步调用来检查整个系统继续处理消息是否安全,并将其插入到处理结束和下一个 receive 的开始之间。监听套接字——甚至选择进入 receive在系统过载的情况下无需重新激活套接字,但您的进程同时需要处理其他 Erlang 消息。

想象一个名为 sysmon 的命名进程驻留在此节点上并检查外部数据库是否过载。您的进程可以接收数据包,对其进行处理,并在允许套接字向其发送另一条消息之前让系统监视器知道它已准备好进行更多工作。系统监视器还可以向监听进程发送消息,告诉它们在监听数据包时暂时停止接收数据包,这对于 gen_tcp:recv 来说是不可能的。方法(因为您要么接收套接字数据,要么检查 Erlang 消息,但不能同时接收两者):

loop(S = {Socket, OtherState}) ->
sysmon ! {self(), ready},
receive
{tcp, Socket, Data} ->
ok = process_data(Data, OtherState),
loop(S);
{tcp_closed, Socket} ->
retire(OtherState),
ok;
{sysmon, activate} ->
inet:setopts(Socket, [{active, once}]),
loop(S);
{sysmon, deactivate} ->
inet:setopts(Socket, [{active, false}]),
loop(S);
{other, message} ->
system_stuff(OtherState),
loop(S)
end.

这是实现系统范围限制的一种方法的开始,可以轻松处理通常最困难的部分:跨网络、系统外部且完全不受您控制的元素。再加上一些早期的决策(比如“在完全拒绝新连接之前我们需要承受多少负载?”),这种将套接字数据作为 Erlang 消息接收的能力,但不会让自己受到它们的轰炸(或填满你的邮箱,使得寻找非套接字消息的成本变得任意昂贵),与我们在石器时代(甚至今天在其他语言中)使用的手动处理套接字的方式相比,感觉非常神奇。

这是 LYSE 的作者 Fred Hebert 关于过载的有趣帖子: "Queues Don't Fix Overload" .这不是 Erlang 特有的,但他所写的想法在 Erlang 中比大多数其他语言更容易实现,这可能与(被误导)使用队列作为容量管理技术的流行有关。

关于erlang - gen_tcp的passive和once模式的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27784622/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com