分类: Erlang2012-08-06 18:55 867人阅读 评论(0) 收藏 举报

首先清楚gen_server提供C/S架构中的服务端的实现,即定义了自己一套规范的服务器框架。

在以上基础上,具体学习下gen_server的实现过程。

先是定义模块的行为模式为gen_server

  1. -module(lqg).
  2. -behaviour(gen_server).
  3. .
  1. -module(lqg).
  2. -behaviour(gen_server).
  3. .
  1. -module(lqg).
  2. -behaviour(gen_server).
  3. .

这里既然用了gen_server框架,那必须要实现gen_server的方法:gen_server callbacks

  1. -export([init/1, handle_call/3, handle_cast/2, handle_info/2,  terminate/2, code_change/3]).
  1. -export([init/1, handle_call/3, handle_cast/2, handle_info/2,  terminate/2, code_change/3]).
  1. -export([init/1, handle_call/3, handle_cast/2, handle_info/2,  terminate/2, code_change/3]).

外加模块的对外调用函数:API

  1. -export([start_link/0]).
  1. -export([start_link/0]).
  1. -export([start_link/0]).
  1. -export([alloc/0,free/1]).
  1. -export([alloc/0,free/1]).
  1. -export([alloc/0,free/1]).

接下来就是实现上面定义的函数:

  1. start_link() ->
  2. gen_server:start_link({local, lqg}, lqg, [], []).
  1. start_link() ->
  2. gen_server:start_link({local, lqg}, lqg, [], []).
  1. start_link() ->
  2. gen_server:start_link({local, lqg}, lqg, [], []).

对于start_link,
第一个参数为创建一个名为Name的server,现在的情况为在gen_srever将在本地被注册为lqg
第二个参数lqg, 则是回调模块的名字,也就是回调函数所放的那个模块。在这里,接口函数( start_link)和回调函数(init, handle_call 和 handle_cast)。一般来说这是好的编程实践,将代表同一个进程的代码包含在同一个模块中。
第三个参数[], 这个值将被原封不动传递给回调函数init。在这里,init无须任何输入数据将忽略这个参数.
第四个参数[],是参数的列表。
这里要注意的是:
1.gen_server:start_link 是同步的。只有等到gen_server被完全初始化并准备接受请求之后才会返回
2.如果gen_server是某棵监督树的一部分,即gen_server是由一个督程启动的,那么必须使用
gen_server:start_link 。还有另外一个函数 gen_server:start 用于启动一个独立的gen_server,即不是某棵监督树一部分的一个gen_server

  1. init(_Args) ->
  2. {ok, channels()}.
  1. init(_Args) ->
  2. {ok, channels()}.
  1. init(_Args) ->
  2. {ok, channels()}.

在注册名称成功后,新的gen_server进程会调用回调函数lqg:init([])
init返回{ok, State} ,其中State 是gen_server的内部状态。在这里,状态就是可用的频道channels。

  1. alloc() ->
  2. gen_server:call(lqg,alloc).
  1. alloc() ->
  2. gen_server:call(lqg,alloc).
  1. alloc() ->
  2. gen_server:call(lqg,alloc).

同步请求alloc() 用gen_server:call/2 实现.lqg 是gen_server的名字,必须和启动时的名字一样。alloc 是实际的请求
此时,请求以消息的形式发送给这个gen_server。当收到了请求之后,gen_server调用handle_call(Request,From, State) ,它应返回一个元组 {reply, Reply, State1}。Reply是需要回馈给客户端的答复,同时State1 是gen_server的状态的新值。

  1. handle_call(_Request, _From, State) ->
  2. {Ch, State2} = alloc(State),
  3. {reply, Ch, State2}。
  1. handle_call(_Request, _From, State) ->
  2. {Ch, State2} = alloc(State),
  3. {reply, Ch, State2}。
  1. handle_call(_Request, _From, State) ->
  2. {Ch, State2} = alloc(State),
  3. {reply, Ch, State2}。

在这里,应答是分配了的频道Ch 然后gen_server将等待新的请求,并且现在保持了一个最新的可用频道的列表。

  1. handle_cast({free,Ch},Chs) ->
  2. Chs2 = free(Ch,Chs),
  3. {noreply, Chs2}.
  1. handle_cast({free,Ch},Chs) ->
  2. Chs2 = free(Ch,Chs),
  3. {noreply, Chs2}.
  1. handle_cast({free,Ch},Chs) ->
  2. Chs2 = free(Ch,Chs),
  3. {noreply, Chs2}.

在这里,新的状态便是更新过的可用频道列表Chs2 。gen_server现在又可以接受新的请求了。

  1. free(Ch) ->
  2. gen_server:cast(lqg,{free,Ch}).
  1. free(Ch) ->
  2. gen_server:cast(lqg,{free,Ch}).
  1. free(Ch) ->
  2. gen_server:cast(lqg,{free,Ch}).

异步请求free(ch) 使用 gen_server:cast/2 实现
lqg 是gen_server的名称。{free, Ch} 是实际的请求。
请求被装在一个消息中发给gen_server的cast ,这调用了 free ,然后返回了 ok 。当gen_server收到请求之后,它会调用handle_cast(Request, Stats) ,会返回一个元组{noreply, State1} 。 State1 是gen_server状态的新值。

  1. handle_info(_Info, State) ->
  2. {noreply, State}.
  1. handle_info(_Info, State) ->
  2. {noreply, State}.
  1. handle_info(_Info, State) ->
  2. {noreply, State}.

用来处理请求之外的信息。

  1. terminate(_Reason, _State) ->
  2. ok.
  1. terminate(_Reason, _State) ->
  2. ok.
  1. terminate(_Reason, _State) ->
  2. ok.

终止函数,终止正在运行的进程

若gen_server是某个监督树的一部分,则无需停止函数。它的督程会自动终止它;

如果gen_server并非某个监督树的一部分,那么可以用一个停止函数;
如果在终止之前需要进行一些清理工作,那么关闭策略必须是一个超时值,同时gen_server必须在init 函数中设置为捕获退出信号。当gen_server被要求关闭时,它就会调用回调函数terminate(shutdown, State)。

  1. code_change(_OldVsn, State, _Extra) ->
  2. {ok, State}.
  1. code_change(_OldVsn, State, _Extra) ->
  2. {ok, State}.
  1. code_change(_OldVsn, State, _Extra) ->
  2. {ok, State}.

正如其名,此函数用来进行代码版本替换。是server热部署或代码升级时做callback修改进程状态
_OldVsn:旧版本 State:gen_server的内部状态 _Extra:原封不动的传递过来的更新指令
如果更新成功,返回{ok,State2},如果失败返回{error,Reason},并回滚到旧版本。

OTP gen_server的更多相关文章

  1. erlang OTP gen_server 图解分析

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

  2. 使用Erlang和Yaws开发REST式的服务

    看过那张很出名的“Apache vs. Yaws”图么?是不是在考虑你也应该使用Yaws了?这些图给人的第一印象是,Yaws在可伸缩性上具有难以置信的巨大优势,它可以扩展到80000个并行的连接,而 ...

  3. Mochiweb的设计分析

    http://blog.csdn.net/dp0304/article/details/6994435 Web服务器的基本工作大致分3步: 接收HTTP请求: 处理HTTP请求,生成响应内容: 发送响 ...

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

    http://blog.sina.com.cn/s/blog_3fe961ae0101k4p6.html 行为模式其实非常类似于面向对象语言中的接口,至少笔者是这么理解的.OTP行为模式将一些反复出现 ...

  5. [Erlang 0119] Erlang OTP 源码阅读指引

      上周Erlang讨论群里面提到lists的++实现,争论大多基于猜测,其实打开代码看一下就都明了.贴出代码截图后有同学问这代码是哪里找的?   "代码去哪里找?",关于Erla ...

  6. Erlang 104 OTP

    笔记系列 Erlang环境和顺序编程Erlang并发编程Erlang分布式编程YawsErlang/OTP 日期              变更说明 2014-12-21 A Outline, 1 A ...

  7. Gen_server行为分析与实践

    1.简介 Gen_server实现了通用服务器client_server原理,几个不同的客户端去分享服务端管理的资源(如图),gen_server提供标准的接口函数和包含追踪功能以及错误报告来实现通用 ...

  8. 如何设置gen_server在退出时执行相关操作

    如果gen_server在监控树中不需要stop函数,gen_server会由其supervisor根据shutdown策略自动终止掉.如果要在进程终止之前执行清理,shutdown策略必须设定一个t ...

  9. Erlang OTP gen_event

    转自:http://www.myexception.cn/program/1569725.html Erlang OTP gen_event (0) 原英文文档:http://www.erlang.o ...

随机推荐

  1. Java类的加载和对象创建流程的详细分析

    相信我们在面试Java的时候总会有一些公司要做笔试题目的,而Java类的加载和对象创建流程的知识点也是常见的题目之一.接下来通过实例详细的分析一下: package com.test; public ...

  2. Logstash使用介绍

    Logstash介绍 Logstash是一个数据收集处理转发系统,是 Java开源项目. 它只做三件事: 数据输入 数据加工(不是必须的):如过滤,改写等 数据输出   下载安装 logstash是基 ...

  3. 【转载】TCP /IP协议详解

    首先,TCP/IP不是一个协议,而是一个协议族的统称. 里面包括了IP协议,IMCP协议,TCP协议,以及http.ftp.pop3协议等等. TCP/IP协议分层 提到协议分层,我们很容易联想到IS ...

  4. 如何恢复已禁用的console.log?

    如何恢复已禁用的console.log? How to Restore a Disabled console.log?通过将其拉出iframe,在已删除的页面(如twitter)上恢复console. ...

  5. Django project troubleshootings

    1. 当django project文件夹放到cgi-bin目录下面时会出现下面的错误: [Wed Jan 09 01:52:52.611690 2019] [core:notice] [pid 15 ...

  6. ios高级开发之多线程(二)NSThread技术

    多线程技术是有多套解决方案的,那么我们该如何选择呢? 技术方案 简介 语言 线程生命周期 使用频率 pthread 1.一套通用的多线程API 2.适用于UNIX,linux,windows等 3.跨 ...

  7. CSS scroll-behavior和JS scrollIntoView让页面滚动平滑

    转自 https://www.zhangxinxu.com/wordpress/2018/10/scroll-behavior-scrollintoview-%E5%B9%B3%E6%BB%91%E6 ...

  8. 函数嵌套定义,闭包及闭包的应用场景,装饰器,global.nonlocal关键字

    函数的嵌套定义 在一个函数的内部定义另一个函数 为什么要有函数的嵌套定义: 1)函数fn2想直接使用fn1函数的局部变量,可以将fn2直接定义到fn1的内部,这样fn2就可以直接访问fn1的变凉了 2 ...

  9. python日志模块的使用

    学习一下python的日志模块logging,可以参考如下博客,写得很详细 https://www.cnblogs.com/yyds/p/6901864.html https://www.cnblog ...

  10. hql 函数大全

    序号  函数名称 说明 类型 支持 使用方法 备注 1 ABS(n) 取绝对值 数学函数 JPAQL HQL ABS(column_name[数字类型对象属性])   2 SQRT(n) 取平方根 数 ...