gen_server

概要
  通用服务器行为
描述

  行为模块实现服务器的客户端-服务器关系。一个通用的服务器进程使用这个模块将实现一组标准的接口功能,包括跟踪和错误报告功能。它也符合OTP进程监控树。了解更多信息参考OTP设计原则。

  gen_server假定所有特定部分位于一个回调模块,它导出的一组预定义的功能。行为函数和回调函数的关系可以说明如下:

  gen_server module Callback module
  ----------------- ---------------
  gen_server:start_link -----> Module:init/1

  gen_server:call
  gen_server:multi_call -----> Module:handle_call/3

  gen_server:cast
  gen_server:abcast     -----> Module:handle_cast/2

  -               -----> Module:handle_info/2

  -               -----> Module:terminate/2

  -               -----> Module:code_change/3

  如果一个回调函数失败或返回一个错误的值,gen_server将会终止。

  gen_server处理系统消息,它们记录在sys。sys模块可以用来调试gen_server。

  请注意,gen_server并不自动地捕获退出信号,这个必须明确地在回调模块启动。

  除非另作说明,如果指定的gen_server不存在或给出错误参数,该模块所有函数会失败。

  如果一个回调函数指定"hibernate"而不是超时值,该gen_server进程会进入休眠。这也许是有用的,如果服务器预计闲置很长一段时间。不过这个功能应该小心使用,使用休眠意味着至少有两个垃圾收集(休眠又很快唤醒),不是你想做的事情之间,每次调用一个繁忙的服务器。

导出

  1. start_link(Module, Args, Options) -> Result
  2. start_link(ServerName, Module, Args, Options) -> Result
  3.   Types:
  4.     ServerName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}
  5.       Name = atom()
  6.       GlobalName = ViaName = term()
  7.     Module = atom()
  8.     Args = term()
  9.     Options = [Option]
  10.       Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}
  11.       Dbgs = [Dbg]
  12.         Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}
  13.       SOpts = [term()]
  14.     Result = {ok,Pid} | ignore | {error,Error}
  15.       Pid = pid()
  16.       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。

  1. start(Module, Args, Options) -> Result
  2. start(ServerName, Module, Args, Options) -> Result
  3.   Types:
  4.      start_link/3,4

  创建一个独立的gen_server进程,也就是,gen_server不是监控树的一部分并且没有监控进程。

  参看start_link/3,4了解参数和返回值的描述。

  1. call(ServerRef, Request) -> Reply
  2. call(ServerRef, Request, Timeout) -> Reply
  3.   Types:
  4.     ServerRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
  5.       Node = atom()
  6.       GlobalName = ViaName = term()
  7.     Request = term()
  8.     Timeout = int()>0 | infinity
  9.     Reply = term()

  通过发送请求向引用名为ServerRef的gen_server进行同步调用,直到回复到达或发生超时。gen_server将调用Module:handle_call/3处理请求。

  ServerRef可以是:

  • 进程号;
  • Name,gen_server被本地注册的名称;
  • {Name,Node},gen_server在其它节点被本地注册;
  • {global,GlobalName},gen_server被全局注册;
  • {via,Module,ViaName},gen_server通过替代的进程注册表注册;

  Request是一个任意term,它作为其中的参数传递给Module:handle_call/3。

  Timeout是一个大于零的整数,它指定多少毫秒等待每个回复,原子infinity会无限期的等待。默认值是5000。如果在指定时间内没有收到回复,函数会调用失败。如果调用者捕获失败并且继续运行,服务器仅仅晚些回复,它将在任何时候到达随后进入调用者的消息队列。对此,调用者必须准备这种情况,并且不保存任何垃圾消息,它们是两个元素元组作为第一个元素。

  返回值Reply被定义在Module:handle_call/3的返回值里。

  调用可能会因为几种原因失败,包括超时和在调用前和调用过程中gen_server死掉。

  在调用期间当连接到客户端,如果服务器死掉,有时会消耗退出消息,这个过时的行为已经在OTP R12B/Erlang 5.6中移除。

  1. multi_call(Name, Request) -> Result
  2. multi_call(Nodes, Name, Request) -> Result
  3. multi_call(Nodes, Name, Request, Timeout) -> Result
  4.   Types:
  5.     Nodes = [Node]
  6.       Node = atom()
  7.     Name = atom()
  8.     Request = term()
  9.     Timeout = int()>=0 | infinity
  10.     Result = {Replies,BadNodes}
  11.       Replies = [{Node,Reply}]
  12.         Reply = term()
  13.       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的返回值里。

  为避免随后的应答(在超时之后)污染调用者的消息队列,一个中间人进程被用来做实际的调用。当它们到达一个终止的进程,迟到的回复将不会被保存。

  1. cast(ServerRef, Request) -> ok
  2.   Types:
  3.   ServerRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
  4.     Node = atom()
  5.     GlobalName = ViaName = term()
  6.   Request = term()

  发送一个异步请求到引用名ServerRef的gen_server,然后立即返回ok,如果目标节点或gen_server不存在,忽略消息。gen_server将调用Module:handle_cast/2处理请求。

  参看call/2,3,了解ServerRef的描述。

  Request是一个任意term,它作为其中的参数传递给Module_cast/2。

  1. abcast(Name, Request) -> abcast
  2. abcast(Nodes, Name, Request) -> abcast
  3.   Types:
  4.     Nodes = [Node]
  5.       Node = atom()
  6.     Name = atom()
  7.     Request = term()

  发送一个异步请求给在指定节点被本地注册为Name的gen_server。函数立即返回并且忽略不存在的节点,或gen_server Name不存在。gen_server将调用Module:handle_cast/2处理请求。

  参看 multi_call/2,3,4,了解参数描述。

  1. reply(Client, Reply) -> Result
  2.   Types:
  3.     Reply = term()
  4.     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没有被进一步定义,并且应该总是被忽略。

  1. enter_loop(Module, Options, State)
  2. enter_loop(Module, Options, State, ServerName)
  3. enter_loop(Module, Options, State, Timeout)
  4. enter_loop(Module, Options, State, ServerName, Timeout)
  5.   Types:
  6.     Module = atom()
  7.     Options = [Option]
  8.       Option = {debug,Dbgs}
  9.         Dbgs = [Dbg]
  10.           Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}
  11.     State = term()
  12.     ServerName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}
  13.       Name = atom()
  14.       GlobalName = ViaName = term()
  15.     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注册。

回调函数

  1. Module:init(Args) -> Result
  2.   Types:
  3.     Args = term()
  4.     Result = {ok,State} | {ok,State,Timeout} | {ok,State,hibernate} | {stop,Reason} | ignore
  5.       State = term()
  6.       Timeout = int()>=0 | infinity
  7.       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。

  1. Module:handle_call(Request, From, State) -> Result
  2.   Types:
  3.     Request = term()
  4.     From = {pid(),Tag}
  5.     State = term()
  6.     Result = {reply,Reply,NewState} | {reply,Reply,NewState,Timeout} | {reply,Reply,NewState,hibernate}
  7.       | {noreply,NewState} | {noreply,NewState,Timeout} | {noreply,NewState,hibernate}
  8.       | {stop,Reason,Reply,NewState} | {stop,Reason,NewState}
  9.       Reply = term()
  10.       NewState = term()
  11.       Timeout = int()>=0 | infinity
  12.       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),随后终止。

  1. Module:handle_cast(Request, State) -> Result
  2.   Types:
  3.     Request = term()
  4.     State = term()
  5.     Result = {noreply,NewState} | {noreply,NewState,Timeout} | {noreply,NewState,hibernate} | {stop,Reason,NewState}
  6.       NewState = term()
  7.       Timeout = int()>=0 | infinity
  8.       Reason = term()

  无论何时,gen_server接收一个请求发送使用gen_server:cast/2 或 gen_server:abcast/2,3,该函数被调用处理请求。

  参见Module:handle_call/3了解参数和可能返回值的描述。

  1. Module:handle_info(Info, State) -> Result
  2.   Types:
  3.     Info = timeout | term()
  4.     State = term()
  5.     Result = {noreply,NewState} | {noreply,NewState,Timeout} | {noreply,NewState,hibernate} | {stop,Reason,NewState}
  6.       NewState = term()
  7.       Timeout = int()>=0 | infinity
  8.       Reason = normal | term()

  该函数被gen_server调用,当超时发生或接收到其它消息而不是同步或异步请求(或者系统消息)。

  Info是原子timeout,当超时发生,或是已接收的消息。

  1. Module:terminate(Reason, State)
  2.   Types:
  3.     Reason = normal | shutdown | {shutdown,term()} | term()
  4.     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已经设置为退出信号;
  • 并且,被定义在监控者的子规范的关闭策略是一个整数值,而不是brutal_kill。

  即使gen_server不是监控者的一部分,如果收到来自父进程的'EXIT'消息,函数将被调用。Reason将和'EXIT'消息一样。

  否则,gen_server将立即终止。

  注意,除了normal,shutdown,或{shutdown,Term}的其他原因,gen_server被设定终止由于一个错误,并且使用error_logger:format/2报告一个错误。

  1. Module:code_change(OldVsn, State, Extra) -> {ok, NewState} | {error, Reason}
  2.   Types:
  3.     OldVsn = Vsn | {down, Vsn}
  4.       Vsn = term()
  5.     State = NewState = term()
  6.     Extra = term()
  7.     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},正在进行的升级将会失败,并且回滚到老版本。

  1. Module:format_status(Opt, [PDict, State]) -> Status
  2.   Types:
  3.     Opt = normal | terminate
  4.     PDict = [{Key, Value}]
  5.     State = term()
  6.     Status = term()

  请注意,该回调可选,所以回调模块不需要导出它,这个回调模块提供一个默认实现,该函数返回回调模块状态。

  该函数被gen_server进程调用:

  • sys:get_status/1,2被调用获取gen_server状态。这种情况,Opt被设置成normal。
  • gem_server异常终止,生成错误日志。这种情况,Opt被设置成terminate。

  该函数是有用的,对于这些情况定制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的返回值一致。

  该函数的一个用法是返回紧凑的替换状态表示来避免有过大的状态项打印在日志里。

Erlang模块gen_server翻译的更多相关文章

  1. Erlang模块erl翻译

    命令:     erl 概述:     Erlang模拟器 描述:     erl程序启动一个Erlang运行时系统.准确的信息是依赖于系统的(举例,erl是否是脚本或程序,其它程序调用).     ...

  2. Erlang模块file翻译

    模块摘要     文件接口模块   描述     模块file提供了文件系统的接口.     在具有线程支持的操作系统上,可以让文件操作以其自己的线程执行,从而允许其他Erlang进程与文件操作并行地 ...

  3. Erlang模块ets翻译

    概要: 内置的存储 描述: 这个模块是Erlang内置存储BIFs的接口.这些提供了在Erlang运行时系统中存储大量数据的能力,并且能够对数据进行持续的访问时间.(在ordered_set的情况下, ...

  4. Erlang模块supervisor翻译

    概要: 通用监督者行为   描述: 一个实现监督者的行为模块,一个监督被称为子进程的其它进程的进程.一个子进程可以是另一个监督者或工作者进程.工作者进程通常的实现使用gen_event,gen_fsm ...

  5. Erlang模块gen_fsm翻译

    模块摘要     通用有限状态机行为.   描述     用于实现有限状态机的行为模块.使用该模块实现的通用有限状态机进程(gen_fsm)将具有一组标准的接口函数,并包括用于跟踪和错误报告的功能.它 ...

  6. Erlang模块gen_tcp翻译

    概述 TCP/IP套接字接口 描述 gen_tcp模块提供了使用TCP / IP协议与套接字进行通信的功能. 以下代码片段提供了一个客户端连接到端口5678的服务器的简单示例,传输一个二进制文件并关闭 ...

  7. Erlang模块inet翻译

    模块 inet 模块概述 访问TCP / IP协议. 描述 此模块提供对TCP/IP协议的访问. 另请参阅<ERTS用户指南:Inet配置>,以获取有关如何配置用于IP通信的Erlang运 ...

  8. erlang OTP gen_server 图解分析

    http://www.hoterran.info/otp-gen_server-sourcecode 在阅读erlang的otp源码gen_server.erl的时候,一直想写点什么,用一种最好的方式 ...

  9. Erlang的gen_server的terminate()/2未执行

    官方资料参考: Module:terminate(Reason, State) Types: Reason = normal | shutdown | {shutdown,term()} | term ...

随机推荐

  1. SQL2008实现数据库自动定时备份——维护计划

    在SQL Server中出于数据安全的考虑,所以需要定期的备份数据库.而备份数据库一般又是在凌晨时间基本没有数据库操作的时候进行,所以我们不可能要求管理员 每天守到晚上1点去备份数据库.要实现数据库的 ...

  2. 【原】小写了一个cnode的小程序

    小程序刚出来的第一天,朋友圈被刷屏了,所以趁周末也小玩了一下小程序.其实发觉搭建一个小程序不难,只要给你一个demo,然后自己不断的查看文档,基本就可以入门了,不过对于这种刚出来的东西,还是挺多坑的, ...

  3. Backdoor CTF 2013: 电子取证 250

    0x00 题目 h4x0r厌烦了你对他的城堡的所有攻击,所以他决定报复攻击你,他给你发来一封带有图片的邮件作为警告,希望你能找出他的警告消息:-) 消息的MD5值就是flag. 0x01 解题法1 给 ...

  4. MEAN教程2-Nodejs安装

    安装Node.js稳定版本最简单的办法也是使用二进制文件,Node.js官方网站上提供了下载地址,可用于Linux.Mac OS X和Windows系统.同样要注意下载与目标操作系统架构一致的文件. ...

  5. Spring Boot踩坑之路一

    Takes an opinionated view of building production-ready Spring applications. Spring Boot favors conve ...

  6. 循环语句——do…while语句

    一.do while语句结构 do { 执行语句 } while (条件表达式); 条件表达式必须是trur或false 二.do while语句特点 不论条件是否满足,都先执行一次执行语句 三.示例 ...

  7. Applovin Interview (面经)

    职位:SDE Intern positon 地点: San Jose 轮电面:self introduction what's your interest Concept of "Concu ...

  8. 通过web sql实现增删查改

    <!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8" ...

  9. Mac和Linux系统的:Arp欺骗源码

    linux系统, 简化版的ARP欺骗工具 精简版, 没有很多代码, 只要把准备好的数据, 发送给到网卡接口, 利用这个工具, 可以让局域网内的一台计算机暂时掉线: #include <stdio ...

  10. C# Web.config 配置handlers 和 httpHandlers

    <system.web> <httpHandlers> <add verb="*" path="*.js.axd" type=&q ...