Erlang OTP学习(1)gen_server

在《Programming Erlang》的OTP introduction章节中,作者通过循序渐进的方式,向我们展示了gen_server设计思路,现在做下总结:

在具体看gen_server之前,我们先看一个server通用框架: 

在这个server里,你几乎看不到任何和具体功能相关的东西,它只提供了一个server所具备的基本框架,那它是如何运行的呢? 
当我们调用start函数时,就启动了一个服务,如果服务器接收到一条消息,那么它将会把这条消息转交给Mod:handle_call或者Mod:handle_cast处理 ,然后把执行结果返回给客户端(可选),接着继续等待新消息。

从这个过程中我们不难发现,服务器实际上充当着“代理”的角色,而真正处理客户端请求的其实是另外一个Module(我们称之为:callback模块)

这样有什么好处呢? 我谈谈自己的拙见: 
1.解耦,把服务器功能部分和非公能部分分离,这样可以我们就可以更加专注于服务器功能模块的编写(即callback模块) 
2.复用性,如果我们希望开发一个具有新功能的server,我们可以复用现有的server框架,然后编写具有新功能的callback Module即可

现在我们看一个callback Module例子(它提供了KV存储功能) 

其中init, handle_call方法是用来供server端回调的,而add,find,start方法是供客户端调用的

我们看下执行结果: 

现在我们来简单分析下整个执行流程: 
stroage:start() 启动了一个名为kv_server的服务,并且使用storage模块作为该服务的callback Module, 接着就阻塞在loop方法中,等待着新消息的到来....这时候,当我们调用storage:add(name, diaocow),就向kv_server发送了一条请求消息{add, name, diaocow},当kv_server接受到这条消息后,自己并没有处理,而是转交给他的callback模块storage处理,并且把处理后的结果返回给客户端,,然后继续等待着新消息...

可以看出server模块充当着代理的角色(接受客户端消息 -> 发给callback模块处理 -> 将处理结果返回给客户端),而storage模块一方面给server提供callback(真正负责处理客户端请求),另一方面给客户端提供了可以调用的接口(譬如这里的add和find接口)。

当你需要修改这个server的功能时,只需要修改callback模块即可,是不是非常方便呢  ^_^

---------------------------------------------------------------------华丽分割线-------------------------------------------------------------------

说了那么多,那么gen_server到底是什么呢? 其实它提供了类似上述理念的通用server框架,只不过比我们更加稳健,完善,如果你需要编写具有某个功能的server,使用gen_server可以让你专注于功能本身的编写,即callback模块

那如何编写一个gen_server的callback模块呢?只需三步 
1.给你的callback Module起一个名字 
2.确定需要向外界(客户端)提供的接口 
3.实现gen_server所要求的回调接口
 
  
现在我们使用gen_server重新实现一下KV存储 

运行下程序,一切ok 

现在我们就详细解释下new_storage模块中每个方法的作用:

1.-behaviour(gen_server) 
它表示让编译器检查,当前module是否实现了gen_server指定的所有回调接口,若我注释掉某一个回调接口(譬如code_change/3),编译时会报: 

2.gen_server:start_link(ServerName, Module, Args, Options) -> Result 
这个方法用来启动一个server,其中: 
参数ServerName指定了服务名 
参数Module指定了该server的callback模块 
参数Args将作为服务初始化的启动参数(服务初始化时会调用:Module:init([Args])) 
参数Options指定了一些特性参数,通常可以直接使用[]

如果服务启动成功,返回{ok, Pid}

3.Module:init([Args]) 
这个方法会在服务初始化时被回调,参数Args就是gen_server:start_link中倒数第二个参数,若初始化成功,该方法放回{ok, State},其中State将作为启动服务的State

4.gen_server:call(ServerRef, Request) 
这个方法供callback模块向ServerRef代表的服务发送Request请求(callback模块通常会在之上再封装一层接口供客户端调用,譬如这里的add,find方法),注意该方法是一个同步调用,它会一直等待服务器返回一个响应消息(除非等待超时,默认5s)

5.Module:handle_call(Request, From, State) -> Result 
这是一个回调方法,用来处理gen_server:call(ServerRef, Request)发出的请求,其中: 
Request,表示客户端请求 
From,表示请求来自哪个客户端 
State,表示当前服务器状态

Result为handle_call 请求处理结果,它有以下几种类型 
{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开头,那么Reply将会作为响应返回给客户端 
如果返回的是以noreply开头,那么服务器将不会返回任何消息给客户端(这会导致客户端阻塞,因为客户端调用的gen_server:call方法是一个同步调用,当它发出请求后,会一直等待服务器发送响应消息,除非等待超时)

6.gen_server:cast(ServerRef, Request) 
这个方法同gen_server:call(ServerRef, Request),但它最大的区别就是该调用是异步的,它不需要等待服务器返回任何处理结果

7.Module:handle_cast(Request, State) -> Result 
这个方法用来处理gen_server:cast(ServerRef, Request)发出的请求,由于不会返回结果给客户端,所以参数列表中也没有From

关于gen_server更多api,请参看:http://www.erlang.org/doc/man/gen_server.html 
otp官方文档:http://www.erlang.org/doc/design_principles/gen_server_concepts.html

现在我们已经把gen_server设计的大体思想说了一遍,即:gen_server实现了一个通用server框架,若我们需要开发某功能,只需要按照gen_server回调接口规范,编写相应的callback Module即可

时间: 2024-08-25 03:17:10

Erlang OTP学习(1)gen_server的相关文章

Erlang OTP学习:supervisor [转]

转自: http://diaocow.iteye.com/blog/1762895 今天细致的看了下supervisor,现在做个总结: 其中,方块代表supervisor process,它的功能很简单,就负责看管它下面的“小弟”(child processes) 并且在必要的时候对某个child process执行restart或者terminate操作:而圆形就代表worker process,它才是真正负责干活的process:特别注意,supervisor process 监控的不一定

Erlang OTP学习(1)gen_fsm

1. 有限状态机 有限状态机可以用下面这个公式来表达 State(S) x Event(E) -> Actions(A), State(S') 表示的就是在S状态时如果有事件E发生,那么执行动作A后把状态调整到S’.理解很好理解,如果能够熟练应用必须得下苦功,多练习. start_link跟gen-sever 类似,启动后进入init初始化,结果是 ok,StateName,State. 此例子中是初始化密码门的原始密码,置输入密码为空 2. 一个例子 erlang手册中用这个例子来解释的:开锁

erlang OTP gen_server 图解分析

http://www.hoterran.info/otp-gen_server-sourcecode 在阅读erlang的otp源码gen_server.erl的时候,一直想写点什么,用一种最好的方式表达出来,最终却总是没法表达清楚,困惑之余看到这篇文章,作者用图解的方式,非常清晰明了的表达了我一直想表达的东西,下面是原文链接: http://www.hoterran.info/otp-gen_server-sourcecode 感谢原创作者热心的分享. 阅读OTP源码可以帮助你写出更好.更健壮

Erlang OTP编程初体验——gen_server和行为模式

http://blog.sina.com.cn/s/blog_3fe961ae0101k4p6.html 行为模式其实非常类似于面向对象语言中的接口,至少笔者是这么理解的.OTP行为模式将一些反复出现的模式分成了两个部分,通用部分和具体应用相关的实现部分,这一过程其实就类似于面向对象编程中的抽象出接口的过程.本文给出一个OTP中最常见的行为模式的示例:通用服务器,即gen_server. 编写gen_server回调模块大致包括3相步骤: (1) 确定回调模块的名称: (2) 写接口函数(由客户

理解Erlang/OTP Supervisor

http://www.cnblogs.com/me-sa/archive/2012/01/10/erlang0030.html Supervisors are used to build an hierarchical process structure called a supervision tree, a nice way to structure a fault tolerant application.                                         

Erlang generic standard behaviours -- gen_server system msg

这是Erlang generic standard behaviors gen_server 分析的系列的最后一篇,主要分析gen_server module 辅助性的功能函数. 在gen_server 的MAIN loop 流程中,除了处理Parent 的'EXIT' 消息, user module 常规消息之外, 还处理了一类 system 消息. 这一类system 消息的来源是一个sys 的module,在Erlang OTP体系中,sys module 主要有两大类的作用,一个是热更,

启动erlang/OTP里面的Web服务器

erlang OTP是一个完整可靠的大型库,乃前人艰苦卓绝之成就:现在尝试一下里面的application inets的Web服务器httpd,写一段代码调用inets服务: 1 -module(inets_httpd). 2 -export([start/0]). 3 4 start() -> 5 inets:start(), 6 inets:start(httpd, [{bind_address, {192,168,178,130}}, {ipfamily, inet}, {port, 18

标准 Erlang/OTP 行为

参考资料 http://erlang.shiningray.cn/otp-design-principles/index.html 标准 Erlang/OTP 行为有: gen_server 用于实现 C/S 结构中的服务端. gen_fsm 用于实现有限状态机. gen_event 用于实现事件处理功能. supervisor 用于实现监督树中的督程.

[Erlang 0127] Term sharing in Erlang/OTP 上篇

之前,在 [Erlang 0126] 我们读过的Erlang论文 提到过下面这篇论文: On Preserving Term Sharing in the Erlang Virtual Machine 地址: http://user.it.uu.se/~kostis/Papers/erlang12_sharing.pdf  摘要:In this paper we describe our experiences and argue through examples why ?attening t