Ranch模塊的作用是什么,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長期合作伙伴,公司提供的服務(wù)項(xiàng)目有:申請域名、雅安服務(wù)器托管、營銷軟件、網(wǎng)站建設(shè)、富蘊(yùn)網(wǎng)站維護(hù)、網(wǎng)站推廣。
此模塊是ranch調(diào)用的一個模塊,用來處理所有的監(jiān)聽和網(wǎng)絡(luò)連接中心。
該模塊的創(chuàng)建時(shí)由ranch:start_listener函數(shù)啟動的基于監(jiān)督者進(jìn)程ranch_sup的子進(jìn)程
erlang的map結(jié)構(gòu) #{},#{name =>"test"} 注意區(qū)分兩種表達(dá)式: =>(可以用來更新映射和創(chuàng)建新的映射) :=(只能更新映射,在鍵不存在時(shí)會拋出異常)
start_link:創(chuàng)建supervisor進(jìn)程,并且將創(chuàng)建這個進(jìn)程的參數(shù)保存到ranch_server中。
1.Ref 監(jiān)聽者實(shí)例別名
2.Transport socket進(jìn)程的創(chuàng)建者
3.protocol 實(shí)際的功能執(zhí)行者
init:ranch_listener_sup進(jìn)程創(chuàng)建成功的調(diào)用函數(shù)。
主要做了下面的事情:
1.創(chuàng)建子進(jìn)程ranch_conns_sup,傳入的參數(shù)有Ref,Transport,Protocol三個。這個進(jìn)程的功能是管理所有的外部連接。
2.創(chuàng)建子進(jìn)程ranch_acceptors_sup,傳入?yún)?shù)是Ref,Transport(可選兩種:tcp,ssl).這個進(jìn)程就是實(shí)際的對外端口監(jiān)聽者
3.將該進(jìn)程的{Ref,self()(自己的進(jìn)程pid)}存入到ranch_server
4.進(jìn)程是以reset_for_one的方式啟動這兩個進(jìn)程,則表明這兩個進(jìn)程是有依賴關(guān)系的。如果ranch_conns_sup掛了,則一定也會掛掉ranch_acceptors_sup,然后重新一次重啟這兩個進(jìn)程
5.實(shí)際中,ranch_acceptors_sup的啟動是依賴ranch_conns_sup進(jìn)程的,所以,必須ranch_conns_sup進(jìn)程必須先啟動
接受socket連接的進(jìn)程,創(chuàng)建Protocol進(jìn)程,并且監(jiān)控這些進(jìn)程的退出
start_link:這個進(jìn)程必須的,因?yàn)樵撨M(jìn)程是以supervisor創(chuàng)建的子進(jìn)程,必須有此函數(shù)。
該進(jìn)程不是gen_server的標(biāo)準(zhǔn),而是采用原始的proc_lib:start_link創(chuàng)建的進(jìn)程,傳入的參數(shù)包括 父進(jìn)程id,Ref,Transport,Protocol
init:通過start_link函數(shù)調(diào)用本模塊的init函數(shù)。
該函數(shù)做了一下的功能:
1.設(shè)置process_flag(trap_exit,true),標(biāo)識是可以接受link模塊的退出信息
2.設(shè)置{Ref,self()}到ranch_server保存數(shù)據(jù)
3.從ranch_server和TransOpts中獲取相應(yīng)的初始化信息,并保存到loop循環(huán)的#state中
4.proc_lib:init_ack(Parent, {ok, self()}) 這是是內(nèi)部的proc_lib的實(shí)現(xiàn),標(biāo)識告訴父進(jìn)程,進(jìn)程創(chuàng)建成功了,并會返回給父進(jìn)程一個{ok,Pid(當(dāng)前創(chuàng)建進(jìn)程的pid)}
loop:執(zhí)行主要的邏輯
1.{?MODULE,start_protocol, To, Socket}:socket收到連接,發(fā)送該進(jìn)程,創(chuàng)建Protocol進(jìn)程。在此進(jìn)程創(chuàng)建的時(shí)候需要注意,實(shí)例進(jìn)程創(chuàng)建進(jìn)程的返回值一定要注意,{ok, Pid}表示自己對自己進(jìn)程關(guān)閉負(fù)責(zé),而{ok,SupPid,ProtocolPid}則表示,該進(jìn)程是有一個conns_sup進(jìn)程來管理這些啟動的進(jìn)程。此處ranch是提供了兩種方法來處理。
2.{?MODULE,active_connections,To,Tag}:獲取該進(jìn)程激活的連接數(shù)
3.{remove_connection, Ref,Pid}:移除連接,此處注意,當(dāng)前只是計(jì)數(shù)減一,并沒有真正的關(guān)閉進(jìn)程 4.{set_max_conns}:重新設(shè)置最大的連接數(shù),如果sleeper里面有數(shù)據(jù),則會將這些鏈接重新啟用 5.{‘EXIT’,Parent,Reason}:此處Parent指的是ranch_listener_sup進(jìn)程,如果父進(jìn)程關(guān)閉,則無條件的關(guān)閉啟動的所有連接進(jìn)程
6.{'EXIT',Pid,Reason}:link的進(jìn)程關(guān)閉了,則清理pid.此處要注意,該進(jìn)程link的pid不能設(shè)置process_flag(trap_exit,true),負(fù)責(zé)就不會收到此斷開信息。如果有睡眠的連接進(jìn)程等待,則激活這些連接進(jìn)程。
7.{system,From,Request}:調(diào)用系統(tǒng)的指令.gen_server的terminate,code_change函數(shù)都和此有關(guān)系。目前看到的支持3中大類,1.suspended 掛起 2.running 獲取一些模塊的信息 3.terminating 關(guān)閉進(jìn)程
8.{'$gen_call', {To, Tag}, Request(which_children,count_children)}:To:標(biāo)識是From,即發(fā)起者的進(jìn)程pid,Tag=erlang:monitor(process,Process)即發(fā)起者監(jiān)聽接受方的MRef信息,在收到信息后,取消monitor,并返回信息。并且此種請求時(shí)通過同步的方式請求。具體的調(diào)用方法是:gen_server:call(SupPid,which_children)的方式請求
start_protocol:此方法由socket進(jìn)程發(fā)起,同步創(chuàng)建實(shí)例,執(zhí)行l(wèi)oop的第一種情況
active_connections:同步請求活躍的連接數(shù),和loop的第8中情況相似,也可以已第8種情況替代
handshake:此方法大調(diào)用于loop的第1中情況,將啟動的實(shí)例進(jìn)程pid和socket進(jìn)行綁定。并且驗(yàn)證,啟動實(shí)例。如果當(dāng)前的連接數(shù)已滿,則阻塞住socket進(jìn)程。如果條件滿足,則確認(rèn)綁定成功。
terminate(#stat{shutdown=brutal_kill},Reason,):關(guān)閉此進(jìn)程,此函數(shù)是有system觸發(fā)的,system_terminate()函數(shù)調(diào)用terminate,直接結(jié)束。brutal_kill標(biāo)識是直接kill掉。
terminate(#state{shutdown=integer()}):表示是非直接關(guān)閉,等待進(jìn)程的自我了斷。
kill_children:直接殺死進(jìn)程,殺死前unlinke(Pid),避免收到進(jìn)程殺死的信息
shutdown_children,wait_children:這兩個函數(shù)時(shí)相互配合使用的,在exit(P,shutdown)成功時(shí),會收到wait_children的{‘DOWN,,process,Pid,’}的信息,顯示的知道有多少個進(jìn)程被中斷。
system_continue,system_terminate,system_code_change:這三個函數(shù),是配合system的命令在sys模塊默認(rèn)調(diào)用的,目前來看,主要有3個功能,system_continue:用來獲取一些進(jìn)程的信息;system_terminate:用來系統(tǒng)中斷進(jìn)程;system_code_change:用來進(jìn)程一些數(shù)據(jù)的更新處理
report_error:對錯誤寫日志記錄
設(shè)置監(jiān)聽socket,將此socket同時(shí)分發(fā)給ranch_accpetor 接受者,監(jiān)聽連接
start_link:啟動進(jìn)程的入口,使用supervisor的模式啟動進(jìn)程
init:1.獲取連接監(jiān)督者,獲取Transport的配置信息,更具配置的監(jiān)聽連接數(shù),通過one_for_one的方式創(chuàng)建一定數(shù)量的監(jiān)聽連接進(jìn)程,來監(jiān)聽外部連接
recevie 的機(jī)制
%% 通過設(shè)置receive after 0,優(yōu)先處理{alarm,X}的消息。因?yàn)樵诔瑫r(shí)時(shí)間為0的receive中,會立即觸發(fā)一個超時(shí),但是在此之前, 系統(tǒng)會嘗試對郵箱進(jìn)行模式匹配,所以此方法,可以對消息優(yōu)先處理,可以用于清空郵箱中的所有消息。 1.優(yōu)先匹配例子 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一個進(jìn)程時(shí),timeout了,但是call 的進(jìn)程也會執(zhí)行完消息處理?
節(jié)選自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.
從上面代碼中可以看到,是在本地進(jìn)程monitor了被call的進(jìn)程,并且erlang:send的方式發(fā)送信息,此時(shí)再receive一個阻塞等待結(jié)果返回,然后再TimeOut的時(shí)候,如果還沒有返回,則返回給進(jìn)程exit(timeout)的錯誤信息。所以,就會出現(xiàn),雖然timeout了,被調(diào)的進(jìn)程還是會處理完,而不能當(dāng)作被調(diào)進(jìn)程沒有收到處理。
如何避免?:1,從源頭避免,確保call的進(jìn)程處理信息足夠簡單,不超時(shí) 2.采用cast,或 ! 替代處理
參考網(wǎng)址:Erlang中帶超時(shí)的receive
此模塊用來接收外部的socket連接。并通知ranch_conns_sup通知業(yè)務(wù)進(jìn)程啟動并且綁定到該socket進(jìn)程
start_link:次數(shù)采用原始的spawn_link函數(shù)啟動一個進(jìn)程,返回{ok, Pid}
loop:1.通過Transport:accept阻塞進(jìn)程,直到接收到一個連接進(jìn)來,然后綁定該連接的socket先到connsSup上,然后調(diào)用ranch_conns_sup:start_protocol啟動一個實(shí)例進(jìn)程,進(jìn)行綁定。
{ok, CSocket}:標(biāo)識連接成功,并且創(chuàng)建了一個連接的socket,進(jìn)行啟動和綁定操作
{error,emfile}:大量的并發(fā)操作調(diào)用,導(dǎo)致操作系統(tǒng)的文件描述符數(shù)量被瞬間用完,拋出emfile.此處應(yīng)為會同時(shí)創(chuàng)建多個連接進(jìn)程,和多個外部的socket連接,則必然會出現(xiàn)此種情況。在晚上看到過,有人在使用了1024個連接,https之后,就會出現(xiàn)問題,導(dǎo)致連接不成功。貼上網(wǎng)址如下:http://erlang.org/pipermail/erlang-questions/2015-January/082446.html
{error,closed}:表明listening socket 關(guān)閉了
?MODULE:loop(_):此方法是可以保證,在版本更新時(shí),總是調(diào)用到最新的模塊函數(shù)
flush:每一次循環(huán)是,都清空掉該進(jìn)程接收到的其他非accepotr消息
關(guān)于連接出現(xiàn){error,emfile}的問題:
1.此錯誤標(biāo)識同時(shí)創(chuàng)建了多個鏈接進(jìn)程,導(dǎo)致操作系統(tǒng)的文件描述符數(shù)量被瞬間用完導(dǎo)致。
2.有兩種I/O處理,一個異步和一個同步。異步I/O下,這個會比較容易實(shí)現(xiàn),需要給予一定的過載保護(hù),防止過分壓榨底層系統(tǒng)的性能。
3.兩種方式:1、設(shè)置 ulimit -n 10480 2.修改 /etc/security/limit.conf文件的句柄數(shù)量
limit.conf ## #* 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.參考網(wǎng)址:
[erlang-questions] {error,emfile}
從EMFILE和ENFILE說起,fd limit的問題(一)
EMFILE,too many open files的解決方案
1.如果設(shè)置cert密匙,客戶端是如何發(fā)送的,并且服務(wù)器又是如何驗(yàn)證的
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。