gen_servernode
概要:
通用服務器行爲
描述:服務器
行爲模塊實現服務器的客戶端-服務器關係。一個通用的服務器進程使用這個模塊將實現一組標準的接口功能,包括跟蹤和錯誤報告功能。它也符合OTP進程監控樹。瞭解更多信息參考OTP設計原則。
gen_server假定全部特定部分位於一個回調模塊,它導出的一組預約義的功能。行爲函數和回調函數的關係能夠說明以下:
gen_server module Callback module
----------------- ---------------
gen_server:start_link -----> Module:init/1app
gen_server:call
gen_server:multi_call -----> Module:handle_call/3異步
gen_server:cast
gen_server:abcast -----> Module:handle_cast/2函數
- -----> Module:handle_info/2oop
- -----> Module:terminate/2atom
- -----> Module:code_change/3
若是一個回調函數失敗或返回一個錯誤的值,gen_server將會終止。
gen_server處理系統消息,它們記錄在sys。sys模塊能夠用來調試gen_server。
請注意,gen_server並不自動地捕獲退出信號,這個必須明確地在回調模塊啓動。
除非另做說明,若是指定的gen_server不存在或給出錯誤參數,該模塊全部函數會失敗。spa
若是一個回調函數指定"hibernate"而不是超時值,該gen_server進程會進入休眠。這也許是有用的,若是服務器預計閒置很長一段時間。不過這個功能應該當心使用,使用休眠意味着至少有兩個垃圾收集(休眠又很快喚醒),不是你想作的事情之間,每次調用一個繁忙的服務器。hibernate
導出:debug
start_link(Module, Args, Options) -> Result start_link(ServerName, Module, Args, Options) -> Result Types: ServerName = {local,Name} | {global,GlobalName} | {via,Module,ViaName} Name = atom() GlobalName = ViaName = term() Module = atom() Args = term() Options = [Option] Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts} Dbgs = [Dbg] Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}} SOpts = [term()] Result = {ok,Pid} | ignore | {error,Error} Pid = pid() Error = {already_started,Pid} | term()
建立一個gen_server進程做爲監控樹的一部分。函數應該直接或間接地被supervisor調用。它將確保gen_server在其它方面被連接到supervisor。
gen_server進程調用Module:init/1進行初始化。爲確保同步啓動過程,start_link/3,4直到Module:init/1執行完成才能返回。
若是ServerName={local,Name},gen_server使用register/2被註冊爲本地的Name。若是ServerName={global,GlobalName},gen_server使用global:register_name/2被註冊爲全局的GlobalName。若是沒有提供Name,gen_server不會被註冊。若是ServerName={via,Module,ViaName},gen_server將會用Module表明的註冊表註冊。Module回調應該導出函數register_name/2, unregister_name/1, whereis_name/1 和 send/2,它們表現得像global模塊對應的函數。所以,{via,global,GlobalName}是一個有效地引用。
Module是回調模塊的名稱。
Args是任意term,做爲參數傳遞給Module:init/1。
若是選項是{timeout,Time},gen_server被容許花費Time毫秒初始化,或者它將被終止,而且啓動函數返回{error,timeout}。
若是選項是{debug,Dbgs},對於Dbgs裏的每一個條目,對應的sys函數將會被調用。參見sys。
若是選項是{spawn_opt,SOpts},SOpts將被做爲選項列表傳遞給spawn_opt內建函數,它被用來產生gen_server。
若是gen_server被成功建立和初始化,函數返回{ok,Pid},其中Pid是gen_server的進程號。若是已經存在使用指定ServerName的進程,函數返回{error,{already_started,Pid}},其中,Pid是那個進程的進程號。
若是Module:init由於Reason失敗,函數返回{error,Reason}。若是Module:init/1返回{stop,Reason} 或 ignore,進程被終止而且函數會分別返回{error,Reason} 或 ignore。
start(Module, Args, Options) -> Result start(ServerName, Module, Args, Options) -> Result Types: 同 start_link/3,4。
建立一個獨立的gen_server進程,也就是,gen_server不是監控樹的一部分而且沒有監控進程。
參看start_link/3,4瞭解參數和返回值的描述。
call(ServerRef, Request) -> Reply call(ServerRef, Request, Timeout) -> Reply Types: ServerRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid() Node = atom() GlobalName = ViaName = term() Request = term() Timeout = int()>0 | infinity Reply = term()
經過發送請求向引用名爲ServerRef的gen_server進行同步調用,直到回覆到達或發生超時。gen_server將調用Module:handle_call/3處理請求。
ServerRef能夠是:
Request是一個任意term,它做爲其中的參數傳遞給Module:handle_call/3。
Timeout是一個大於零的整數,它指定多少毫秒等待每一個回覆,原子infinity會無限期的等待。默認值是5000。若是在指定時間內沒有收到回覆,函數會調用失敗。若是調用者捕獲失敗而且繼續運行,服務器僅僅晚些回覆,它將在任什麼時候候到達隨後進入調用者的消息隊列。對此,調用者必須準備這種狀況,而且不保存任何垃圾消息,它們是兩個元素元組做爲第一個元素。
返回值Reply被定義在Module:handle_call/3的返回值裏。
調用可能會由於幾種緣由失敗,包括超時和在調用前和調用過程當中gen_server死掉。
在調用期間當鏈接到客戶端,若是服務器死掉,有時會消耗退出消息,這個過期的行爲已經在OTP R12B/Erlang 5.6中移除。
multi_call(Name, Request) -> Result multi_call(Nodes, Name, Request) -> Result multi_call(Nodes, Name, Request, Timeout) -> Result Types: Nodes = [Node] Node = atom() Name = atom() Request = term() Timeout = int()>=0 | infinity Result = {Replies,BadNodes} Replies = [{Node,Reply}] Reply = term() BadNodes = [Node]
對全部在指定節點上被本地註冊爲Name的gen_server進行同步調用,經過第一次發送請求到每一個節點,而後等待回覆。這些gen_server進程將會調用Module:handle_call/3處理請求。
函數返回元組{Replies,BadNodes},其中,Replies是{Node,Reply}的列表,BadNodes是不存在節點的列表,或gen_server Name不存在或沒有回覆。
Nodes是請求被髮送到的節點名稱列表。默認值是中全部已知的節點列表[node()|nodes()]。
Name是每一個gen_server被本地註冊的名稱。
Request是一個任意term,它做爲其中的參數傳遞給Module:handle_call/3。
Timeout是一個大於零的整數,它指定多少毫秒等待每一個回覆,原子infinity會無限期的等待。默認值是infinity。若是在指定時間內節點沒有收到回覆,該節點被加入到BadNodes。
當在節點Node來自gen_server回覆Reply到達,{Node,Reply}被加入到Replies。Reply被定義在Module:handle_call/3的返回值裏。
爲避免隨後的應答(在超時以後)污染調用者的消息隊列,一箇中間人進程被用來作實際的調用。當它們到達一個終止的進程,遲到的回覆將不會被保存。
cast(ServerRef, Request) -> ok Types: ServerRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid() Node = atom() GlobalName = ViaName = term() Request = term()
發送一個異步請求到引用名ServerRef的gen_server,而後當即返回ok,若是目標節點或gen_server不存在,忽略消息。gen_server將調用Module:handle_cast/2處理請求。
參看call/2,3,瞭解ServerRef的描述。
Request是一個任意term,它做爲其中的參數傳遞給Module_cast/2。
abcast(Name, Request) -> abcast abcast(Nodes, Name, Request) -> abcast Types: Nodes = [Node] Node = atom() Name = atom() Request = term()
發送一個異步請求給在指定節點被本地註冊爲Name的gen_server。函數當即返回而且忽略不存在的節點,或gen_server Name不存在。gen_server將調用Module:handle_cast/2處理請求。
參看 multi_call/2,3,4,瞭解參數描述。
reply(Client, Reply) -> Result Types: Reply = term() Result = term()
當回覆沒有定義在Module:handle_call/3的返回值裏,該函數能夠被gen_server用來顯式地發送回覆給一個調用 call/2,3 或 multi_call/2,3,4的客戶端。
Client必須是提供給回調函數的From參數。Reply是一個任意term,它將做爲call/2,3 或 multi_call/2,3,4的返回值被回覆到客戶端。
返回Result沒有被進一步定義,而且應該老是被忽略。
enter_loop(Module, Options, State) enter_loop(Module, Options, State, ServerName) enter_loop(Module, Options, State, Timeout) enter_loop(Module, Options, State, ServerName, Timeout) Types: Module = atom() Options = [Option] Option = {debug,Dbgs} Dbgs = [Dbg] Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}} State = term() ServerName = {local,Name} | {global,GlobalName} | {via,Module,ViaName} Name = atom() GlobalName = ViaName = term() Timeout = int() | infinity
使一個已存在的進程進入一個gen_server。不返回,反而這個調用進程將進入gen_server的接收循環,併成爲一個gen_server進程。這個進程必須使用proc_lib的啓動函數被啓動。用戶爲該進程的任何初始化負責,包括爲它註冊一個名字。
這個函數很是有用,當須要一個更加複雜的初始化過程,而不是gen_server行爲提供的。
Module,Option 和ServerName與調用gen_server:start[_link]/3,4有着相同的含義。然而,若是ServerName被指定,進程必須在該函數被調用前相應地被註冊。
State和Timeout與Module:init/1的返回值有着相同的含義。回調模塊Module也不須要導出一個init/1函數。
失敗:若是調用進程未被一個proc_lib函數啓動,或者若是它未依據ServerName註冊。
回調函數
Module:init(Args) -> Result Types: Args = term() Result = {ok,State} | {ok,State,Timeout} | {ok,State,hibernate} | {stop,Reason} | ignore State = term() Timeout = int()>=0 | infinity Reason = term()
不管什麼時候一個gen_server使用gen_server:start/3,4 或 gen_server:start_link/3,4被啓動,該函數被一個新進程調用去初始化。
Args是提供給啓動函數的參數。
若是初始化成功,函數應該返回{ok,State}, {ok,State,Timeout} 或 {ok,State,hibernate},其中,State是gen_server的內部狀態。
若是一個整數超時值被提供,一個超時將發生,除非在Timeout毫秒內收到一個請求或消息。一個超時被timeout原子標識,它應該被handle_info/2回調函數處理。infinity能夠被用來無限期地等待,這是默認值。
若是hibernate被指定而不是一個超時值,進程將進入休眠當等待下一條消息到達時(調用proc_lib:hibernate/3)。
若是在初始化期間出現錯誤,函數返回{stop,Reason},其中,Reason是任何term,或ignore。
Module:handle_call(Request, From, State) -> Result Types: Request = term() From = {pid(),Tag} State = term() Result = {reply,Reply,NewState} | {reply,Reply,NewState,Timeout} | {reply,Reply,NewState,hibernate} | {noreply,NewState} | {noreply,NewState,Timeout} | {noreply,NewState,hibernate} | {stop,Reason,Reply,NewState} | {stop,Reason,NewState} Reply = term() NewState = term() Timeout = int()>=0 | infinity Reason = term()
不管什麼時候使用gen_server:call/2,3 或 gen_server:multi_call/2,3,4,gen_server接收請求發送,該函數被調用處理請求。
Request是提供給call或multi_call的參數。
From是一個元組{Pid,Tag},其中,Pid是客戶端的進程號,Tag是一個惟一標誌。
State是gen_server的內部狀態。
若是函數返回{reply,Reply,NewState}, {reply,Reply,NewState,Timeout} 或 {reply,Reply,NewState,hibernate},Reply將被回覆給From做爲call/2,3 或 multi_call/2,3,4的返回值。而後gen_server繼續執行,可能更新內部狀態NewState。參看Module:init/1瞭解Timeout和hibernate的描述。
若是函數返回{noreply,NewState}, {noreply,NewState,Timeout} 或 {noreply,NewState,hibernate},gen_server將用NewState繼續執行。任何對From的回覆必須顯式使用gen_server:reply/2。
若是函數返回{stop,Reason,Reply,NewState},Reply將回復給From。若是函數返回{stop,Reason,NewState},任何對From的回覆必須顯式使用gen_server:reply/2。而後,函數將調用Module:terminate(Reason,NewState),隨後終止。
Module:handle_cast(Request, State) -> Result Types: Request = term() State = term() Result = {noreply,NewState} | {noreply,NewState,Timeout} | {noreply,NewState,hibernate} | {stop,Reason,NewState} NewState = term() Timeout = int()>=0 | infinity Reason = term()
不管什麼時候,gen_server接收一個請求發送使用gen_server:cast/2 或 gen_server:abcast/2,3,該函數被調用處理請求。
參見Module:handle_call/3瞭解參數和可能返回值的描述。
Module:handle_info(Info, State) -> Result Types: Info = timeout | term() State = term() Result = {noreply,NewState} | {noreply,NewState,Timeout} | {noreply,NewState,hibernate} | {stop,Reason,NewState} NewState = term() Timeout = int()>=0 | infinity Reason = normal | term()
該函數被gen_server調用,當超時發生或接收到其它消息而不是同步或異步請求(或者系統消息)。
Info是原子timeout,當超時發生,或是已接收的消息。
Module:terminate(Reason, State) Types: Reason = normal | shutdown | {shutdown,term()} | term() State = term()
該函數被gen_server調用,當它準備終止。它應該和Module:init/1相反,並作必要的清理。當它返回時,gen_server因爲Reason終止。返回值被忽略。
Reason是一個term,指出中止緣由,State是gen_server的內部狀態。
Reason取決於gen_server終止的緣由。若是由於另外一個回調函數已經返回一箇中止元組{stop,..},Reason將會有指定的值在那個元組。若是是因爲失敗,Reason是錯誤緣由。
若是gen_server是監控樹的一部分,而且被監控者有序終止,該函數將被調用,使用Reason=shutdown,若是應用如下狀態:
即便gen_server不是監控者的一部分,若是收到來自父進程的'EXIT'消息,函數將被調用。Reason將和'EXIT'消息同樣。
不然,gen_server將當即終止。
注意,除了normal,shutdown,或{shutdown,Term}的其餘緣由,gen_server被設定終止因爲一個錯誤,而且使用error_logger:format/2報告一個錯誤。
Module:code_change(OldVsn, State, Extra) -> {ok, NewState} | {error, Reason} Types: OldVsn = Vsn | {down, Vsn} Vsn = term() State = NewState = term() Extra = term() Reason = term()
該函數被gen_server調用,當它在版本升級/降級應該更新本身的內部狀態,也就是說,當指令{update,Module,Change,...}在appup文件中被給出,其中Change={advanced,Extra}。參看OTP設計原則查看更多信息。
在升級的狀況下,OldVsn就是Vsn;在降級的狀況下,OldVsn就是{down,Vsn}。Vsn被回調模塊Module的老版本的vsn屬性定義。若是沒有這樣的屬性定義,版本就是BEAM文件的校驗和。
State是gen_server的內部狀態。
Extra來自升級指令的{advanced,Extra}部分,被原樣傳遞。
若是成功,函數應該返回被更新的內部狀態。
若是函數返回{error,Reason},正在進行的升級將會失敗,而且回滾到老版本。
Module:format_status(Opt, [PDict, State]) -> Status Types: Opt = normal | terminate PDict = [{Key, Value}] State = term() Status = term()
請注意,該回調可選,因此回調模塊不須要導出它,這個回調模塊提供一個默認實現,該函數返回回調模塊狀態。
該函數被gen_server進程調用:
該函數是有用的,對於這些狀況定製gen_server的格式和表現。一個回調模塊但願定製sys:get_status/1,2的返回值,和它在終止錯誤日誌的狀態表現,導出一個format_status/2實例,返回描述gen_server當前狀態的term。 PDict是gen_server的進程字典的當前值。 State是gen_server的內部狀態。 函數應該返回Status,定製當前狀態的細節和gen_server的狀態的term。在Status格式上沒有任何限制,可是對於sys:get_status/1,2狀況,對於Status建議的格式是[{data, [{"State", Term}]}],其中,Term提供gen_server相關的細節。遵循這些建議不是必須的,可是這樣作將使回調模塊的狀態與sys:get_status/1,2的返回值一致。 該函數的一個用法是返回緊湊的替換狀態表示來避免有過大的狀態項打印在日誌裏。