您好,登錄后才能下訂單哦!
Ranch模塊的作用是什么,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
此模塊是ranch調用的一個模塊,用來處理所有的監聽和網絡連接中心。
該模塊的創建時由ranch:start_listener函數啟動的基于監督者進程ranch_sup的子進程
erlang的map結構 #{},#{name =>"test"} 注意區分兩種表達式: =>(可以用來更新映射和創建新的映射) :=(只能更新映射,在鍵不存在時會拋出異常)
start_link:創建supervisor進程,并且將創建這個進程的參數保存到ranch_server中。
1.Ref 監聽者實例別名
2.Transport socket進程的創建者
3.protocol 實際的功能執行者
init:ranch_listener_sup進程創建成功的調用函數。
主要做了下面的事情:
1.創建子進程ranch_conns_sup,傳入的參數有Ref,Transport,Protocol三個。這個進程的功能是管理所有的外部連接。
2.創建子進程ranch_acceptors_sup,傳入參數是Ref,Transport(可選兩種:tcp,ssl).這個進程就是實際的對外端口監聽者
3.將該進程的{Ref,self()(自己的進程pid)}存入到ranch_server
4.進程是以reset_for_one的方式啟動這兩個進程,則表明這兩個進程是有依賴關系的。如果ranch_conns_sup掛了,則一定也會掛掉ranch_acceptors_sup,然后重新一次重啟這兩個進程
5.實際中,ranch_acceptors_sup的啟動是依賴ranch_conns_sup進程的,所以,必須ranch_conns_sup進程必須先啟動
接受socket連接的進程,創建Protocol進程,并且監控這些進程的退出
start_link:這個進程必須的,因為該進程是以supervisor創建的子進程,必須有此函數。
該進程不是gen_server的標準,而是采用原始的proc_lib:start_link創建的進程,傳入的參數包括 父進程id,Ref,Transport,Protocol
init:通過start_link函數調用本模塊的init函數。
該函數做了一下的功能:
1.設置process_flag(trap_exit,true),標識是可以接受link模塊的退出信息
2.設置{Ref,self()}到ranch_server保存數據
3.從ranch_server和TransOpts中獲取相應的初始化信息,并保存到loop循環的#state中
4.proc_lib:init_ack(Parent, {ok, self()}) 這是是內部的proc_lib的實現,標識告訴父進程,進程創建成功了,并會返回給父進程一個{ok,Pid(當前創建進程的pid)}
loop:執行主要的邏輯
1.{?MODULE,start_protocol, To, Socket}:socket收到連接,發送該進程,創建Protocol進程。在此進程創建的時候需要注意,實例進程創建進程的返回值一定要注意,{ok, Pid}表示自己對自己進程關閉負責,而{ok,SupPid,ProtocolPid}則表示,該進程是有一個conns_sup進程來管理這些啟動的進程。此處ranch是提供了兩種方法來處理。
2.{?MODULE,active_connections,To,Tag}:獲取該進程激活的連接數
3.{remove_connection, Ref,Pid}:移除連接,此處注意,當前只是計數減一,并沒有真正的關閉進程 4.{set_max_conns}:重新設置最大的連接數,如果sleeper里面有數據,則會將這些鏈接重新啟用 5.{‘EXIT’,Parent,Reason}:此處Parent指的是ranch_listener_sup進程,如果父進程關閉,則無條件的關閉啟動的所有連接進程
6.{'EXIT',Pid,Reason}:link的進程關閉了,則清理pid.此處要注意,該進程link的pid不能設置process_flag(trap_exit,true),負責就不會收到此斷開信息。如果有睡眠的連接進程等待,則激活這些連接進程。
7.{system,From,Request}:調用系統的指令.gen_server的terminate,code_change函數都和此有關系。目前看到的支持3中大類,1.suspended 掛起 2.running 獲取一些模塊的信息 3.terminating 關閉進程
8.{'$gen_call', {To, Tag}, Request(which_children,count_children)}:To:標識是From,即發起者的進程pid,Tag=erlang:monitor(process,Process)即發起者監聽接受方的MRef信息,在收到信息后,取消monitor,并返回信息。并且此種請求時通過同步的方式請求。具體的調用方法是:gen_server:call(SupPid,which_children)的方式請求
start_protocol:此方法由socket進程發起,同步創建實例,執行loop的第一種情況
active_connections:同步請求活躍的連接數,和loop的第8中情況相似,也可以已第8種情況替代
handshake:此方法大調用于loop的第1中情況,將啟動的實例進程pid和socket進行綁定。并且驗證,啟動實例。如果當前的連接數已滿,則阻塞住socket進程。如果條件滿足,則確認綁定成功。
terminate(#stat{shutdown=brutal_kill},Reason,):關閉此進程,此函數是有system觸發的,system_terminate()函數調用terminate,直接結束。brutal_kill標識是直接kill掉。
terminate(#state{shutdown=integer()}):表示是非直接關閉,等待進程的自我了斷。
kill_children:直接殺死進程,殺死前unlinke(Pid),避免收到進程殺死的信息
shutdown_children,wait_children:這兩個函數時相互配合使用的,在exit(P,shutdown)成功時,會收到wait_children的{‘DOWN,,process,Pid,’}的信息,顯示的知道有多少個進程被中斷。
system_continue,system_terminate,system_code_change:這三個函數,是配合system的命令在sys模塊默認調用的,目前來看,主要有3個功能,system_continue:用來獲取一些進程的信息;system_terminate:用來系統中斷進程;system_code_change:用來進程一些數據的更新處理
report_error:對錯誤寫日志記錄
設置監聽socket,將此socket同時分發給ranch_accpetor 接受者,監聽連接
start_link:啟動進程的入口,使用supervisor的模式啟動進程
init:1.獲取連接監督者,獲取Transport的配置信息,更具配置的監聽連接數,通過one_for_one的方式創建一定數量的監聽連接進程,來監聽外部連接
recevie 的機制
%% 通過設置receive after 0,優先處理{alarm,X}的消息。因為在超時時間為0的receive中,會立即觸發一個超時,但是在此之前, 系統會嘗試對郵箱進行模式匹配,所以此方法,可以對消息優先處理,可以用于清空郵箱中的所有消息。 1.優先匹配例子 priority_receive()-> receive {alarm,X}-> after 0-> receive Any-> Any end end. 2.清空郵箱所有消息 flush(Logger) -> receive Msg -> ranch:log(warning, "Ranch acceptor received unexpected message: ~p~n", [Msg], Logger), flush(Logger) after 0 -> ok end.
拓展:為什么在call一個進程時,timeout了,但是call 的進程也會執行完消息處理?
節選自gen.erl do_call(Process, Label, Request, Timeout) -> try erlang:monitor(process, Process) of Mref -> %% If the monitor/2 call failed to set up a connection to a %% remote node, we don't want the '!' operator to attempt %% to set up the connection again. (If the monitor/2 call %% failed due to an expired timeout, '!' too would probably %% have to wait for the timeout to expire.) Therefore, %% use erlang:send/3 with the 'noconnect' option so that it %% will fail immediately if there is no connection to the %% remote node. catch erlang:send(Process, {Label, {self(), Mref}, Request}, [noconnect]), receive {Mref, Reply} -> erlang:demonitor(Mref, [flush]), {ok, Reply}; {'DOWN', Mref, _, _, noconnection} -> Node = get_node(Process), exit({nodedown, Node}); {'DOWN', Mref, _, _, Reason} -> exit(Reason) after Timeout -> erlang:demonitor(Mref, [flush]), exit(timeout) end catch error:_ -> %% Node (C/Java?) is not supporting the monitor. %% The other possible case -- this node is not distributed %% -- should have been handled earlier. %% Do the best possible with monitor_node/2. %% This code may hang indefinitely if the Process %% does not exist. It is only used for featureweak remote nodes. Node = get_node(Process), monitor_node(Node, true), receive {nodedown, Node} -> monitor_node(Node, false), exit({nodedown, Node}) after 0 -> Tag = make_ref(), Process ! {Label, {self(), Tag}, Request}, wait_resp(Node, Tag, Timeout) end end.
從上面代碼中可以看到,是在本地進程monitor了被call的進程,并且erlang:send的方式發送信息,此時再receive一個阻塞等待結果返回,然后再TimeOut的時候,如果還沒有返回,則返回給進程exit(timeout)的錯誤信息。所以,就會出現,雖然timeout了,被調的進程還是會處理完,而不能當作被調進程沒有收到處理。
如何避免?:1,從源頭避免,確保call的進程處理信息足夠簡單,不超時 2.采用cast,或 ! 替代處理
參考網址:Erlang中帶超時的receive
此模塊用來接收外部的socket連接。并通知ranch_conns_sup通知業務進程啟動并且綁定到該socket進程
start_link:次數采用原始的spawn_link函數啟動一個進程,返回{ok, Pid}
loop:1.通過Transport:accept阻塞進程,直到接收到一個連接進來,然后綁定該連接的socket先到connsSup上,然后調用ranch_conns_sup:start_protocol啟動一個實例進程,進行綁定。
{ok, CSocket}:標識連接成功,并且創建了一個連接的socket,進行啟動和綁定操作
{error,emfile}:大量的并發操作調用,導致操作系統的文件描述符數量被瞬間用完,拋出emfile.此處應為會同時創建多個連接進程,和多個外部的socket連接,則必然會出現此種情況。在晚上看到過,有人在使用了1024個連接,https之后,就會出現問題,導致連接不成功。貼上網址如下:http://erlang.org/pipermail/erlang-questions/2015-January/082446.html
{error,closed}:表明listening socket 關閉了
?MODULE:loop(_):此方法是可以保證,在版本更新時,總是調用到最新的模塊函數
flush:每一次循環是,都清空掉該進程接收到的其他非accepotr消息
關于連接出現{error,emfile}的問題:
1.此錯誤標識同時創建了多個鏈接進程,導致操作系統的文件描述符數量被瞬間用完導致。
2.有兩種I/O處理,一個異步和一個同步。異步I/O下,這個會比較容易實現,需要給予一定的過載保護,防止過分壓榨底層系統的性能。
3.兩種方式:1、設置 ulimit -n 10480 2.修改 /etc/security/limit.conf文件的句柄數量
limit.conf #<domain> <type> <item> <value> # #* soft core 0 #* hard rss 10000 #@student hard nproc 20 #@faculty soft nproc 20 #@faculty hard nproc 50 #ftp hard nproc 0 #@student - maxlogins 4 * soft nproc 65535 * hard nproc 65535 * soft nofile 65535 * hard nofile 65535 # End of file
4.參考網址:
[erlang-questions] {error,emfile}
從EMFILE和ENFILE說起,fd limit的問題(一)
EMFILE,too many open files的解決方案
1.如果設置cert密匙,客戶端是如何發送的,并且服務器又是如何驗證的
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。