sockets - 一个监听多个进程的套接字
问题描述
我有一个非常简单的问题,我想创建 20 个子进程,每个子进程都有相同的监听套接字,有 2 种方法我只想知道两者之间有什么区别:
module(sup).
.....
start() ->
supervisor:start_link({local,?MODULE},?MODULE,[]).
%%%%%%%%%%%%%%%%%%
--------第一种方法------
init([]) ->
Listen=gen_tcp:listen(....),
spawn(fun() ->start_children(20) end),
{ok,{{simple_one_for_one,5,1},[{child,{ChildModule,start,[Listen]},....}]}}.
%%%%%%%%%%%%%%%%%
start_children(N) ->
[supervisor:start_child(?MODULE, [])||_ <-lists:seq[1,N]],
ok.
这是一个 simple_one_for_one 树,我只是创建一个侦听套接字并将其设置为每个启动的进程的参数,这些进程将在稍后处理它,我产生了一个新进程来运行start_children/1
,因为这个函数调用了主管,后来它在它的init/1
函数中并且它在它自己开始之前无法启动子进程,因此该进程将等待 sup 的启动来调用它,让我们看看第二种方法:---------第二种方法---------
init([]) ->
ChildSpecs=[{Id,{ChildModule,start,[fun createListenSocket/0]},....}||Id <-lists:seq[1,20]]
{ok,{{one_for_one,5,1},ChildSpecs}}.
%%%%%%%%%%%%%%%%%%%%
createListenSocket() ->
gen_tcp:listen(....).
这是一个 one_for_one 树,sup 在开始时创建了 20 个孩子,有 20 个套接字:每个孩子一个套接字,所以问题是:这两种方法是相同的还是不同的?如果我们认为它们是相同的,这意味着侦听套接字只是一个变量,并且套接字中的特殊事物(侦听传入连接)在我们运行时开始gen_tcp:accept/1
。因为如果不是,我们会遇到第一种方法中 20 个进程共享同一个侦听套接字的情况。
编辑 :
好的,我认为 José 已经回答了我的问题,但他的回答给了我另一个问题:如何在 Erlang 中创建多个具有相同端口和 IP 地址的套接字?因为如果我想为每个节点运行 20 个套接字,则 ip 是本地 ip 地址,并且所有套接字都相同,并且端口也相同,如果我只需要一个指定的应用程序端口?有一个选项{reuseaddr, true}
作为参数,gen_tcp:listen
但它只能在我们为不同的 IP 地址使用相同的端口并且reuseport
在 Erlang 中没有时才可以使用,那么该怎么做呢?
解决方案
免责声明:这个答案是关于 Linux 的。
不,这两种方法不一样,监听套接字是操作系统结构。一个创建一个侦听套接字,另一个创建 20 个侦听套接字(或者至少尝试这样做,因为最后 19 个将失败,除非您启用端口重用。您在这个问题中对此选项有一个很好的解释)。
您可以检查监听套接字sudo ss -punta | grep LISTEN
在具有多个侦听套接字的操作系统级别,连接的负载平衡由内核执行,忽略同级套接字是否有任何操作系统线程等待accept
. 因此,在拥有单个侦听套接字时,您可能会在接受队列中遇到争用,而拥有多个侦听套接字时,您可能会看到延迟差异,因为一个 OS 线程具有更多负载。(在此 cloudflare 博客条目中有详细说明)
编辑:
reuseport
仅适用于新的低级套接字接口,如果您使用gen_tcp
,则仅reuseaddr
可用。
话虽如此,请记住,当您在 erlang 中时,您是上面的一层:阻塞gen_tcp:accept
不需要是(而且很可能不是 *) a OS-level blocking accept
。同样,我之前提到的 OS 线程不是 erlang 线程,而是 BEAM 调度程序。在大多数情况下,拥有一个监听套接字就可以了。
*由于依赖于 erlang 代码的调度程序(OS 线程)和任意数量的套接字数量有限,因此blocking accept
使用epoll
.
推荐阅读
- python-2.7 - 使用退格会在 raw_input 中添加一些 utf 字符
- java - 按下按钮时不会重置时间
- javascript - 如何从 Accuweather api 获取城市的唯一 ID?
- php - FFI API 受限
- python-3.x - 在 Tkinter 中动态调整图像大小
- django - django模板网址问题
- wix - WiX 安装程序添加注册表项的问题
- evernote - 有没有办法在 Evernote iOS SDK 中将笔记转换为 HTML 文件
- react-native - 无法让 Appium 与 Expo 在设备或模拟器上运行(这甚至可能吗?)
- laravel - How to show microsoft graph calendar in a webpage