好记性,不如烂鼻头!!
说明我们的事例都是来自《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}).