我有一個非常簡單的問題,我想創建 20 個子行程,每個子行程都有相同的監聽套接字,有兩種方法我只想知道兩者之間有什么區別:
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 中沒有,那么該怎么做呢?
uj5u.com熱心網友回復:
免責宣告:這個答案是關于 Linux 的。
不,這兩種方法不一樣,監聽套接字是作業系統結構。一個創建一個偵聽套接字,另一個創建 20 個偵聽套接字(或至少嘗試這樣做,因為最后 19 個將失敗,除非您啟用埠重用。您在這個問題中有關于此選項的精彩解釋)。
您可以檢查偵聽套接字 sudo ss -punta | grep LISTEN
在具有多個偵聽套接字的作業系統級別,連接的負載平衡由內核執行,忽略同級套接字是否有任何等待accept. 因此,當只有一個偵聽套接字時,您可能會在接受佇列中遇到爭用,而擁有多個偵聽套接字時,您可能會看到延遲差異,因為一個作業系統執行緒具有更多負載。(在此 cloudflare 博客條目中對此進行了詳細說明)
編輯:
reuseport僅適用于新的低級套接字介面,如果您使用gen_tcp,則僅reuseaddr可用。
話雖如此,請記住,當您在 erlang 中時,您是上層:阻塞gen_tcp:accept不需要是(并且很可能不是 *) a OS-level blocking accept。同樣,我之前提到的 OS 執行緒也不是 erlang 執行緒,而是 BEAM 調度程式。在大多數情況下,只有一個監聽套接字就可以了。
*由于在調度器(OS執行緒)的有限量的和依賴于Erlang的代碼插座的任意數量,這將會是一個惡夢使用blocking accept代替epoll。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/328762.html
標籤:插座 通讯协议 二郎 长生不老药 erlang-otp
下一篇:Socket編程聊天應用
