erlang 学习之OTP 中 gen_server (一)

阅读更多

好记性,不如烂鼻头!!

 

说明我们的事例都是来自《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}).




 

 

你可能感兴趣的:(erlang,gen_server)