erlang杂记三 --- 服务器抽象

来源:互联网 发布:网络监测平台 编辑:程序博客网 时间:2024/05/01 22:01

一:第一版服务器程序:

start(Name,Mod)->register(Name,spawn(fun()->loop(Name, Mod, mod:init())end)).rpc(Name,Request)->Name ! {self(), Request},receive{Name, Response} -> Responseend.loop(Name, Mod, State)->receive{From, Request}->{Response, State1} = Mod:handle(Request, State),From ! {Name, Respinse},loop(Name, Mod, State1)end.init()->dict:new().add(Name, Place)->rpc(name_server, {add, Name, Place}).handle({add, Name, Place}, Dict)->{ok, dict:store(Name, Place, Dict)}.

调用方法就是先调用start/2 启动一个server,调用add/2,就可以完成服务器的处理。
这里首先是start/2函数,这个函数新建了一个进程给loop使用,在loop调用之前,先对环境及状态进行设置:init/0函数。
loop此时等待客户消息。客户调用add方法,add使用rpc对服务器发送消息,loop对消息匹配后,抵用了mod模块的handle函数处理数据。
数据处理完成后,结果返回,然后尾递归,继续loop。
二:第二个版本:
这个版本没啥好玩儿,说是支持了事务,代码看来,就是loop的时候,对handle过程抓了异常,并将异常信息返回,客户收到异常信息,退出。
三:第三个版本:
个人觉得这个才是经典。服务器代码热替换哦~

start(Name, Mod)->register(Name, spawn(fun()->loop(Namem Mod, Mod:init())end)).swap_code(Name, Mod)->rpc(Name, {swap_code,Mod}).rpc(Name, Request)->Name ! {self(),Request}receive{Name, Response}->responseend.loop(Name, Mod, OldState)->receive{From, {swap_code,NewCallBackMod}}->From!{Name, ack},loop(Name, NewCallBackMod, OldState);{From, Request}->{Response, NewState} = Mod:handle(Request, OldState),From ! {Name, Response},loop(Name, Mod, NewStat)end.

他是怎么工作的?当你准备更新代码的时候,只要显式的调用一下swap_code/2这个函数就够了。为什么呢?
本来一切都没变,跟第一个代码相比,如果非要有变化,那也只是loop的时候,会先匹配模式,如果没有匹配到swap_code,那就调用handle并返回结果,继续循环。
现在手动强制使用了swap_code,这个时候,swap_code会通过Rpc将新模块和信息来源一同发送给服务器。服务器解析时匹配到了swap_code,注意,这个时候你什么也没有做,你只是递归了loop,但是变化也就发生在这一刻,这一刻,传到loop里面的东西变了,是新代码的模块名,其他参数没变化。这个结果就是Mod被修改了,下一刻执行调用的时候,Mod带有的handle也变化了,也就完成了代码的更新。打个比方,就是这里是个指针,你更新了指针指向的地址,那么你对这个指针重新解析的话,内容也就是新地址里面的内容了。一定要注意,这里是使用loop自己来记忆自己的Mod的,不是外部传递进来的(除了初始化)。也就是说,mod这个参数的信息是loop自管理的,loop有自己的状态机,当条件满足时,状态机迁移到新的状态,代码更新也就完成了。
四:更好玩儿的服务器

start->spawn(fun()->wait() end).wait()->receive{become, F}->F()end.rpc(Pid, Q)->Pid ! {self(), Q},receive{Pid, Reply}->Replyend.

看到没,代码什么也没做哦~只是启动了衣服等待的空服务。使用方法:
Pid ! {become, fun myFunc:loop/0}.
用这句给服务器发一个命令,服务器收到命令后,自己更新了自己存的函数(自递归的loop),于是当你给服务器发消息的时候,第一次匹配,没匹配到become,第二次匹配发现了loop里内容匹配成功,于是,命令得到解释,结果计算出来了。当发送新的become消息,服务器会更新自己的loop,构成新的服务器。


之前看erlang/otp还没理解作者说的进程是个容器是什么意思,那这里就清晰了,你把什么东西放进去,他就具有有什么功能。个人觉得,这些都依赖于高阶函数,高阶函数将自己(没猜错应该实现上是个函数指针之类)注册到容器中,而容器又不停的把自己存的东西拿出来遛一遛,具有自更新的服务器就这样完成了。

原创粉丝点击