1. 首先我们来看例子1。
- -module(ch1).
- -export([start/0]).
- -export([alloc/0, free/1]).
- -export([init/0]).
- %% 启动频道服务
- start() ->
- spawn(ch1, init, []). %% 创建一个进程,这个进程会调用init方法,参数为[]
- %% 获取一个空闲的频道
- alloc() ->
- ch1 ! {self(), alloc},
- receive
- {ch1, Res} ->
- Res
- end.
- %% 释放一个频道
- free(Ch) ->
- ch1 ! {free, Ch},
- ok.
- %% 初始化频道信息
- init() ->
- register(ch1, self()), %% 注册名称为ch1的进程
- Chs = channels(), %% 调用channels方法获取 {_Allocated = [], _Free = [1,2,3,4,5,...,100]}. _Allocated 列表表示已经占用的频道,_Free 列表表示空闲的频道
- loop(Chs).
- loop(Chs) ->
- receive
- {From, alloc} -> %% 接受到一个获取频道消息
- {Ch, Chs2} = alloc(Chs), %% 调用alloc/1方法,获取一个未被占用的频道
- From ! {ch1, Ch}, %% 发送一个消息到调用者
- loop(Chs2); %% 继续等待消息
- {free, Ch} -> %% 接受到一个释放频道Ch的消息
- Chs2 = free(Ch, Chs), %% 调用free/2,将该频道放入空闲频道列表中
- loop(Chs2) %% 继续等待消息
- end.
- %% 初始化已占用频道列表和空闲频道列表
- channels() ->
- {_Allocated = [], _Free = lists:seq(1,100)}.
- %% 获取一个空闲频道,并放入已占用频道列表中
- alloc({Allocated, [H|T] = _Free}) ->
- {H, {[H|Allocated], T}}.
- %% 将频道Ch从已占用频道列表中移除,放入空闲列表中
- free(Ch, {Alloc, Free} = Channels) ->
- case lists:member(Ch, Alloc) of
- true ->
- {lists:delete(Ch, Alloc), [Ch|Free]};
- false ->
- Channels
- end.
上面那个例子中,主要实现的是 频道服务 功能。用户通过 alloc/0 方法获取一个空闲频道, 通过free/1 去释放一个频道。我已经添加了比较详细的注释
2. 接下来,我们再看一个例子
- -module(server).
- -export([start/1]).
- -export([call/2, cast/2]).
- -export([init/1]).
- start(Mod) ->
- spawn(server, init, [Mod]).
- call(Name, Req) ->
- Name ! {call, self(), Req},
- receive
- {Name, Res} ->
- Res
- end.
- cast(Name, Req) ->
- Name ! {cast, Req},
- ok.
- init(Mod) ->
- register(Mod, self()),
- State = Mod:init(),
- loop(Mod, State).
- loop(Mod, State) ->
- receive
- {call, From, Req} ->
- {Res, State2} = Mod:handle_call(Req, State),
- From ! {Mod, Res},
- loop(Mod, State2);
- {cast, Req} ->
- State2 = Mod:handle_cast(Req, State),
- loop(Mod, State2)
- end.
- -module(ch2).
- -export([start/0]).
- -export([alloc/0, free/1]).
- -export([init/0, handle_call/2, handle_cast/2]).
- %% 启动服务
- start() ->
- server:start(ch2).
- %% 功能定制 获取空闲频道
- alloc() ->
- server:call(ch2, alloc).
- %% 功能定制 释放频道
- free(Ch) ->
- server:cast(ch2, {free, Ch}).
- init() ->
- channels().
- %% 获取频道的回调函数
- handle_call(alloc, Chs) ->
- alloc(Chs). % => {Ch,Chs2}
- %% 释放频道的回调函数
- handle_cast({free, Ch}, Chs) ->
- free(Ch, Chs). % => Chs2
- channels() ->
- {_Allocated = [], _Free = lists:seq(1,100)}.
- alloc({Allocated, [H|T] = _Free}) ->
- {H, {[H|Allocated], T}}.
- free(Ch, {Alloc, Free} = Channels) ->
- case lists:member(Ch, Alloc) of
- true ->
- {lists:delete(Ch, Alloc), [Ch|Free]};
- false ->
- Channels
- end.
我们将例子1中 能够通用的 代码剥离,所谓能够通用就是,如果我们要实现另一个服务器模型,也可以使用 server 服务器来实现。
另一个好处就是,例子1 中,如果你要添加一个消息类型,则需要修改服务器loop函数,而 例子2中,只需要修改定制部分的功能,和新增回调函数就能实现,
那么这样就能保证服务器的通用,稳定。
模块 server 对应的是极大简化了的Erlang/OTP中的 gen_server 行为。
标准 Erlang/OTP 行为有:
gen_server用于实现 C/S 结构中的服务端。gen_fsm用于实现有限状态机。gen_event用于实现事件处理功能。supervisor用于实现监督树中的督程。
from:
http://www.cnblogs.com/yourihua/archive/2012/05/12/2497702.html
阅读(1755) | 评论(0) | 转发(0) |