文件evserv2.erl
-module(evserv2).
-compile(export_all).
-record(state,{events,clients}).
-record(event,{name="",description="",pid,timeout}).
init() ->
loop(#state{events = orddict:new(), clients = orddict:new()}).%初始化,维护2个列表,事件列表和客户端列表
send_to_clients(Msg, ClientDict) ->%发送消息
orddict:map(fun(_Ref, Pid) ->Pid ! Msg end, ClientDict).%根据客户端标签,把消息发送给客户端
loop(S = #state{}) ->%服务器抽象
receive
{Pid, MsgRef, {subscribe, Client}} ->%订阅通知
Ref = erlang:monitor(process, Client),%添加一个监视器
NewClient = orddict:store(Ref,Client,S#state.clients),%把新的客户端添加进客户端列表,记录有事件标签和客户端的标签
Pid ! {MsgRef, ok},%发送确定消息
loop(S#state{clients=NewClient});
{Pid, MsgRef, {add, Name,Description,Timeout}} ->%添加事件通知,Name是唯一的事件标记
EventPid = event:start_link(Name,Timeout),%创建事件进程
NewEvents = orddict:store(Name,%新增一个
#event{
name = Name,%唯一标记
description =Description,%描述
pid = EventPid,%事件进程PID
timeout = Timeout%多少秒后发
},
S#state.events),
Pid ! {MsgRef, ok},
loop(S#state{events = NewEvents});
{Pid, MsgRef, {cancel, Name}} ->%删除事件
Events = case orddict:find(Name,S#state.events) of%根据唯一标签找到事件
{ok, E} ->
events:cancel(E#event.pid),%删除事件进程
orddict:erase(Name, S#state.events);%删除列表中的事件
error ->
S#state.events
end,
Pid ! {MsgRef, ok},
loop(S#state{events=Events});
{done, Name} ->%事件发送事件
case orddict:find(Name, S#state.events) of%先把他找出来是谁做完了
{ok, E} ->
send_to_clients({done, E#event.name,E#event.description},
S#state.clients),%发送消息
NewEvents = orddict:erase(Name, S#state.events),%删除掉 根据唯一ID
loop(S#state{events=NewEvents});
error ->
loop(s)
end;
shutdown ->
exit(shutdown);
{'DOWN', Ref, process, _Pid, _Reason} ->
loop(S#state{clients=orddict:erase(Ref, S#state.clients)});
code_change ->
?MODULE:loop(S);
Unknow ->
io:format("Unknown message: ~p~n",[Unknow]),
loop(S)
end.
start() ->
register(?MODULE, Pid=spawn(?MODULE, init, [])),%注册一个进程,而且唯一,不能重复定义
Pid.
start_link() ->
register(?MODULE, Pid = spawn(?MODULE,init,[])),
Pid.
terminate() ->
?MODULE ! shutdown.
subscribe(Pid) ->%订阅抽象
Ref = erlang:monitor(process, whereis(?MODULE)),
?MODULE ! {self(), Ref, {subscribe, Pid}},%因为服务器唯一 而且使用MODULE标记的 所以可以这样写
receive
{Ref, ok} ->
{ok, Ref};
{'DOWN', Ref, process, _Pid, Reason} ->
{error,Reason}
after 5000 ->
{error, timeout}
end.
add_event(Name, Description, Timeout) ->%添加事件抽象
Ref = make_ref(),
?MODULE ! {self(), Ref, {add, Name,Description,Timeout}},
receive
{Ref, Msg} ->
Msg
after 5000 ->
{error, timeout}
end.
add_event2(Name, Description, Timeout) ->
Ref = make_ref(),
?MODULE ! {self(), Ref, {add, Name,Description,Timeout}},
receive
{Ref, {error, Reason}} -> erlang:error(Reason);
{Ref, Msg} -> Msg
after 5000 ->
{error, timeout}
end.
cancel(Name) ->
Ref = make_ref(),
?MODULE ! {self(), Ref, {cancel, Name}},
receive
{Ref, ok} -> ok
after 5000 ->
{error, timeout}
end.
listen(Deply) ->
receive
M = {done, _Name, _Descrption} ->
[M|listen(0)]
after Deply*1000 ->
[]
end.
文件event.erl
-module(event).
-export([loop/1,start/2,init/3,cancel/1,start_link/2]).
-record(state,{server,name="",to_go=0}).%server发给谁,name信息,go秒数
loop(S = #state{server=Server}) ->
receive
{Server,Ref,cancel} ->
Server ! {Ref, ok}
after S#state.to_go*1000 ->
Server ! {done,S#state.name}
end.
start(Event,Dplay) ->
spawn(?MODULE, init, [self(), Event, Dplay]).
start_link(Event,Dplay) ->
spawn_link(?MODULE, init, [self(), Event, Dplay]).
init(Server,Event,Dplay) ->
loop(#state{server = Server,name = Event, to_go = Dplay}).
cancel(Pid) ->
Ref = erlang:monitor(process, Pid),
Pid ! {self(), Ref, cancel},
receive
{Ref, ok} ->
erlang:demonitor(Ref, [flush]),
ok;
{'DOWN',Ref,process,Pid,_Reason} ->
ok
end.
1.学习到了orrdict的使用,这是erl自带的一个字典,而且key是唯一的,因为这是一个个人用的,所以够用了.
2.学到了一些封装抽象的思想