Erlang --- gen_server
行为模式
gen_server代表的就是“行为模式”的一种,行为模式的目的在于为特定类型的进程提供一套模板。
启动服务器
用来启动服务器的有start/3
,start/4
,start_link/3
,start_link/4
这四个函数。 使用这些start函数之后,就会产生一个新的进程,也就是一个gen_server服务器。这些 start函数的正常情况下返回值是{ok,Pid}
,Pid
就是这个新进程的进程号。 带link与不带的区别在于是否跟父进程建立链接,换种说法是,新启动的进程死掉后,会不会通知启动他的进程(父进程)。
start函数可以四个参数(ServerName, Module, Args, Options)
:
第一个参数
ServerName
是服务名, 是可以省掉的。具有相同服务名的模块在一个节点中只能启动一次,重复启动会报错,为{error, {already_started, Pid}}
。具有服务名的服务进程可以使用服务名来调用, 没有服务名的只能通过进程号pid来调用了。通常有名字的服务进程会使用模块名做为 服务名,即上面模板中定义的宏-define(SERVER, ?MODULE)
,然后在需要使用服务名的 地方填入?SERVER
.第二个参数
Module
是模块名,一般而言API和回调函数是写在同一个文件里的,所以就用?MODULE
,表示本模块的模块名。第三个参数
Args
是回调函数init/1
的参数,会原封不动地传给init/1
。- 第四个参数
Options
是一些选项,可以设置debug、超时等东西。
init/1
,一般来说是进行服务器启动后的一些初始化的工作, 并生成初始的状态State,正常返回是{ok, State}。这个State是贯穿整个服务器, 并把所有六个回调函数联系起来的纽带。它的值最初由init/1
生成, 此后可以由三个handle函数修改,每次修改后又要放回返回值中, 供下一个被调用的handle函数使用。 如果init/1
返回ignore
或{stop, Reason}
,则会中止服务器的启动。
start_link/0
中使用self()
的话,显示的是调用者的进程号,而在init/1
中使用self()
的话,显示的是服务器的进程号。
三个handle开头的回调函数对应着三种不同的使用服务器的方式。如下:
gen_server:call ------------- handle_call/3 gen_server:cast ------------- handle_cast/2 用!向服务进程发消息 ------------- handle_info/2
gen_server:call(ServerRef, Request, Timeout) -> Reply
,
- 第一个参数
ServerRef
是被调用的服务器,可以是服务器名,或是服务器的pid。 - 第二个参数
Request
会直接传给回调函数handle_call。
- 最后一个参数
Timeout
是超时,是可以省略的,默认值是5秒。
call是用来指挥回调函数handle_call/3
干活的。具体形式为 handle_call(Request, From, State)
。
- 第一个参数
Request
是由call传进来的,是写程序时关注和处理的重点。 - 第二个参数
From
是gen_server传进来的,是调用的来源,也就是哪个进程执行了call。From
的形式是{Pid, Ref}
,Pid
是来源进程号,而Ref
是调用的标识,每一次调用 都不一样,用以区别。有了Pid,在需要向来源进程发送消息时就可以使用,但由于call 是有返回值的,一般使用返回值传递数据就好。 - 第三个参数
State
是服务器的状态,这是由init或是其他的handle函数生成的,可以根据需要进 行修改之后,再放回返回值中。
handle_call/3
在正常情况下的返回值是{reply, Reply, NewState}
, Reply
会作为call的返回值传递回去,NewState
则会作为服务器的状态。 另外还可以使用{stop, Reason, State}
中止服务器运行,这比较少用。
使用call要小心的是,两个服务器进程不能互相call,不然会死锁。
cast
cast是没有返回值的调用,一般把它叫做通知。它是一个“异步”的调用,调用后会直接收到 ok
,无需等待回调函数执行完毕。
它的形式是gen_server:cast(ServerRef, Request)
。参数含义 与call相同。由于不需要等待返回,所以没必要设置超时,没有第三个参数。
在多节点的情况下,可以用abcast
,向各节点上的具有指定名字的服务进程发通知。
cast们对应的回调函数是handle_cast/2
,具体为:handle_cast(Msg, State)
。 第一个参数是由cast传进去的,第二个是服务器状态,和call类似,不多说。
handel_cast/2
的返回值通常是{noreply, NewState}
,这可以用来改变服务器状态, 或是{stop, Reason, NewState}
,这会停止服务器。通常来说,停止服务器的命令用 cast来实现比较多。
原生消息
原生消息是指不通过call或cast,直接发往服务器进程的消息,有些书上译成“带外消息”。 比方说网络套接字socket发来的消息、别的进程用!发过来的消息、跟服务器建立链接的进程死掉了, 发来{'EXIT', Pid, Why}
等等。一般写程序要尽量用API,不要直接用!向服务器进程发消息, 但对于socket一类的依赖于消息的应用,就不得不处理原生消息了。
handle_info/2
处理,具体为handle_info(Info, State)
。其中Info是 发过来的消息的内容。回复和handle_cast
是一样的。
上面介绍的handle函数返回{stop,...},就会使用回调函数terminate/2
进行扫尾工作。 典型的如关闭已打开的资源、文件、网络连接,打log做记录,通知别的进程“我要死啦”, 或是“信春哥,满血复活”:利用传进来的状态State重新启动服务器。
转载于:https://www.cnblogs.com/hzy1987/p/5441807.html
Erlang --- gen_server相关推荐
- erlang使用gen_server实现质数服务器(手打代码,还debug了几个错误)
最近简单了解一下erlang语言,操练了一下书里的例子,有机会debug:下面是主要模块 prime_server,使用gen_server作为behaviour: 1 -module(prime_s ...
- 使用go来实现类似erlang otp里面的gen_server功能
erlang比go要成熟,其中一大原因就是拥有otp工程,进程的管理可以通过专门的行为 模式去处理,例如gen_server,里面包含的6个回调函数init/1, handle_call/3, han ...
- [Erlang脚印 0004] gen_server
gen_server:start_link(ServerName, Module, Args, Options) -> Result ServerName={local, Name}|{glob ...
- [Erlang33]使用recon从网页查看Erlang运行状态
recon_web observer web页面查看,不需求wx GUI 需要Erlang安装wx GUI application 保证可以在生产环境中被安全调用 如果对于ets非常多或进程达到一定数 ...
- OTP gen_server
erlang behaviour小结之gen_server OTP入门 分类: Erlang2012-08-06 18:55 867人阅读 评论(0) 收藏 举报 servererlangcallba ...
- 我的erlang TCP服务器
2019独角兽企业重金招聘Python工程师标准>>> 不解释,直接贴代码. 1) socket_options.hrl -record(socket_options,{port=8 ...
- 对Erlang开发者的几点建议
2019独角兽企业重金招聘Python工程师标准>>> * 确保没有任何编译警告 * Erlang中String采用list实现,32位系统中,其1个字符用8个字节的空间(4个保存v ...
- [erlang]proc_lib源码浅析
源码位置位于安装目录的lib/stdlib/src下. 之前在使用gen_server时,由于之前自己实现过一个gen_server,因此对它内部的机制也能知道个七七八八,最近在用erlang的fsm ...
- Erlang OTP学习(3) supervisor
今天细致的看了下supervisor,现在做个总结: 其中,方块代表supervisor process,它的功能很简单,就负责看管它下面的"小弟"(child proces ...
最新文章
- 今天開始學習silverlight了
- IEDA与activiti不兼容等等安装错误问题的解决方案
- Android Interactive Animation
- python九九乘法表代码知乎_二年级上册表内乘法教学反思_二年级6的乘法口诀教学反思...
- js修改地址栏url_在gulp、create-react-app中css,js中的文件路径
- MySQL查看和修改表的存储引擎
- 直接输出数组的名字不一定是地址值
- 云计算实战系列三(Linux文件管理)
- StretchBlt()函数使用
- dwr框架查看外放方法_先睹为快!IntelliJ IDEA v2019.3带来的新框架和新技术
- java 怎么接收xml_Java如何提取完整的XML块
- OpenSSL学习(十四):基础-指令passwd
- 什么是防抖和节流?有什么区别?如何实现?
- eclipse字体大小怎么设置
- Unity3d是目前主流的游戏开发引擎
- Mac修改hosts文件
- oracle11g 测试io,IO性能测试 1:Oracle ORION
- Mac下Android studio怎么格式化代码
- 电脑计算机丢失UxTheme,Win7系统电脑开机提示uxtheme.dll丢失的解决方法
- 第十二周《支持SQl Server内部,第二版》CHAR1数据页面和数据行 作者Dmitri Korotkevitch