好记性,不如烂鼻头!!
说明我们的事例都是来自《erlang程序设计》第16节,但是会做我自己调整,以使其更接近OTP的标准gen_server模版本省。
本例分成三大部分,第一部分 是对《erlang程序设计中的代码》中简单例子进行说明;第二部分是关注如何更快速地编写一个gen_server服务;第三部分是gen_server标准实现源代码分析,看看我们还需要补充什么!!
现在就开始了!
ex1: server1
-module(server1). -export([start/2,rpc/2]). %%启动一个空的等待进程 start(Name, Mod) -> register(Name, spawn(fun() -> loop(Name,Mod, Mod:init())end)). %远程调用接口 rpc(Name,Request) -> Name ! {self(),Request}, receive {Name, Response} -> Response end. loop(Name,Mod,State)-> receive {From,Request}-> %%回到具体的函数处理模块 %%并返回 结果集 和 状态值 {Response , State1} = Mod:handle_call(Request,State), %%返回到到rpc的值 From ! {Name, Response}, %% 采用尾递归技术来循环 loop(Name,Mod,State1) end. -module(name_server1). %%给server1回到函数 -export([init/0,handle_call/2]). -export([add/2,whereis/1]). start()->server1:start(name_server,name_server1). init()->dict:new(). handle_call({add,Name,Place},Dict) -> {ok,dict:store(Name,Place,Dict)}; handle_call({whereis,Name},Dict) ->{dict:find(Name,Dict),Dict}. add(Name,Place) -> server1:rpc(name_server,{add,Name,Place}). whereis(Name) -> server1:rpc(name_server,{whereis,Name}).
ex2:server2 加入异常处理机制
-module(server2). -export([start/2,rpc/2]). start(Name, Mod) -> register(Name, spawn(fun() -> loop(Name,Mod, Mod:init())end)). rpc(Name,Request) -> Name ! {self(),Request}, receive {Name,crash} -> exit(rpc); {Name, ok, Response} -> Response end. loop(Name,Mod,OldState)-> receive {From,Request}-> try Mod:handle_call(Request,OldState) of {Response, NewState} -> From ! {Name,Response}, loop(Name,Mod,NewState) %% 加入了异常处理机制 当出现则回调 terminate函数 请求 catch _:Why -> From ! {Name, crash}, Mod:terminate(Why, OldState) end end. -module(name_server2). %%给server1回到函数 %%增加 中止的回调函数 -export([init/0,handle_call/2, terminate/2 ]). -export([add/2,whereis/1]). start()->server2:start(name_server, name_server2). init()->dict:new(). %%当发生中止时 回调函数 terminate(Reason, State)-> io:format("server caused exception ~p state ~p ~n",[Reason,State]). handle_call({add,Name,Place},Dict) -> {ok,dict:store(Name,Place,Dict)}; handle_call({whereis,Name},Dict) ->{dict:find(Name,Dict),Dict}. add(Name,Place) -> server2:rpc(name_server,{add,Name,Place}). whereis(Name) -> server2:rpc(name_server,{whereis,Name}).
ex3: server3 加入热代码备份
%% --- %% Excerpted from "Programming Erlang", %% published by The Pragmatic Bookshelf. %% Copyrights apply to this code. It may not be used to create training material, %% courses, books, articles, and the like. Contact us if you are in doubt. %% We make no guarantees that this code is fit for any purpose. %% Visit http://www.pragmaticprogrammer.com/titles/jaerlang for more book information. %%--- -module(server3). -export([start/2, rpc/2, swap_code/2]). start(Name, Mod) -> register(Name, spawn(fun() -> loop(Name,Mod,Mod:init()) end)). rpc(Name, Request) -> Name ! {self(), Request}, receive {Name, Response} -> Response end. loop(Name, Mod, OldState) -> receive {From, {swap_code, NewCallBackMod}} -> %% 发送 确认信息到对应的字段 From ! {Name, ack}, %% 开启新的代码处理流程循环 loop(Name, NewCallBackMod, OldState); {From, Request} -> {Response, NewState} = Mod:handle_call(Request, OldState), From ! {Name, Response}, loop(Name, Mod, NewState) end. -module(name_server2). %%给server1回到函数 %%增加 中止的回调函数 -export([init/0,handle_call/2, terminate/2 ]). -export([add/2,whereis/1]). start()->server3:start(name_server, name_server2). init()->dict:new(). %%当发生中止时 回调函数 terminate(Reason, State)-> io:format("server caused exception ~p state ~p ~n",[Reason, State]). handle_call({add,Name,Place},Dict) -> {ok,dict:store(Name,Place,Dict)}; handle_call({whereis,Name},Dict) ->{dict:find(Name,Dict),Dict}. add(Name,Place) -> server3:rpc(name_server,{add,Name,Place}). whereis(Name) -> server3:rpc(name_server,{whereis,Name}). %% 增加热代码替换工作 swap_code(Name, Mod) -> server3:rpc(Name, {swap_code, Mod}).
ex4 综合并加入 状态控制
%% --- %% Excerpted from "Programming Erlang", %% published by The Pragmatic Bookshelf. %% Copyrights apply to this code. It may not be used to create training material, %% courses, books, articles, and the like. Contact us if you are in doubt. %% We make no guarantees that this code is fit for any purpose. %% Visit http://www.pragmaticprogrammer.com/titles/jaerlang for more book information. %%--- -module(server4). -export([start/2, call/2, swap_code/2]). start(Name, Mod) -> register(Name, spawn(fun() -> loop(Name,Mod,Mod:init()) end)). swap_code(Name, Mod) -> call(Name, {swap_code, Mod}). call(Name, Request) -> Name ! {self(), Request}, receive {Name, crash} -> exit(rpc); {Name, ok, Response} -> Response end. %% 加入状态判读 loop(Name, Mod, OldState) -> receive {From, {swap_code, NewCallbackMod}} -> case Mod:code_change(OldState) of {ok, _State}-> From ! {Name, ok, ack}, loop(Name, NewCallbackMod, OldState); {stop, _state}-> From ! {Name, crash} end; {From, Request} -> try Mod:handle_call(Request, OldState) of {reply, Response, NewState} -> From ! {Name, ok, Response}, loop(Name, Mod, NewState); {noreply, NewState} -> loop(Name, Mod, NewState) catch _: Why -> From ! {Name, crash}, Mod:terminate(Why, OldState) end end. -module(name_server4). %%给server1回到函数 %%增加 中止的回调函数 -export([init/0,handle_call/2, code_change/1, terminate/2 ]). -export([add/2,whereis/1]). start()->server3:start(name_server, name_server4). init()->dict:new(). code_change(_State)-> {ok}. %%当发生中止时 回调函数 terminate(Reason, State)-> io:format("server caused exception ~p state ~p ~n",[Reason, State]). handle_call({add,Name,Place},Dict) -> {reply,ok,dict:store(Name,Place,Dict)}; handle_call({whereis,Name},Dict) ->{reply,dict:find(Name,Dict),Dict}. add(Name,Place) -> server4:rpc(name_server,{add,Name,Place}). whereis(Name) -> server4:rpc(name_server,{whereis,Name}). %% 增加热代码替换工作 swap_code(Name, Mod) -> server4:rpc(ok, Name, {swap_code, Mod}).