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的返回值一致。 该函数的一个用法是返回紧凑的替换状态表示来避免有过大的状态项打印在日志里。