gen_server 的回调结构

启动服务器

gen_server:start_link(Name, Mod, InitArgs, Opts) 这个调用是所有事物的起点。它会创建一个名为Name的通用服务器,回调模块是Mod,Opts则控制通用服务器的行为。在这里可以指定消息记录、函数调试和其他行为。通用服务器通过调用Mod:init(InitArgs)启动。
init的模板项
在通常的操作里,只会返回{ok, State},如果返回{ok, State},就说明我们成功启动了服务器,它的初始状态是State。

调用服务器

要调用服务器,客户端程序需要执行gen_server:call(Name, Request)。它最终调用的是Name回调模块里的Name:handle_call/3
handle_call的模板项
参数对应如下

%%调用服务
deposit({Who, Amount}) -> gen_server:call(_Name = ?MODULE, _Request = {add, Who, Amount}).

%%处理调用
handle_call({add, Who, X} = _Request, _From, Tab) ->
	Reply = case ets:lookup(Tab, Who) of
						[] -> not_exist;
						[{Who, Balance}] ->
							NewBalance = Balance + X,
							ets:insert(Tab, {who, NewBalance}),
							{thanks, Who, your_balance_is, NewBalance}
					end,
	{reply, Reply, Tab};

调用和播发

我们已经见过了gen_server:callhandle_call之间的交互,它的作用是实现远程过程调用。gen_server:cast(Name, Msg)则实现了一个播发(cast),也就是没有返回值的调用(实际上就是一个消息,但习惯上称它为播发来与远程过程调用相区分)。
handle_info的模板项
这个处理函数通常只返回{noreply,NewState}或{stop, …}。前者改变服务器的状态,后者停止服务器。

发给服务器的自发性消息

回调函数**handle_info(Info, State)*被用来处理发给服务器的自发性消息。自发性消息是一切未经显式调用gen_server:callgen_server:cast而到达服务器的消息。举个例子,如果服务器连接到另一个进程并捕捉退出信号,就可能会突然收到一个预料之外的{‘EXIT’, Pid, What}消息。除此之外,系统里任何知道通用服务器PID的进程都可以向它发送消息。这样的消息在服务器里表现为info*值。
handle_info的模板项
它的返回值和handle_cast相同。

服务器崩溃和停止

服务器会因为许多原因而终止。某个以handle_开头的函数也许会返回一个{stop, Reason, NewState},服务器也可能崩溃并生成{‘EXIT’, reason}。在所有这些情况下,无论它们是怎样发生的,都会调用terminate(Reason, NewState)。
terminate的模板项
这段代码不能返回一个新状态,因为我们已经终止了。但是了解服务器在终止时的状态非常有用。可以把状态保存到磁盘,把它放入消息发送给别的进程,或者根据应用程序的意愿丢弃它。如果想让服务器过后重启,就必须编写一个“我胡汉三又回来了”的函数,由terminate/2触发。

代码更改

你可以在服务器运行时动态更改它的状态。这个回调函数会在系统执行软件升级时由版本处理子系统调用。
code_change的模版项

最后附上全部代码

-module(my_bank).
-author("Jessamine").

-export([start/1, stop/0, new_account/1, deposit/1, withdraw/1, handle_call/3, handle_info/2, handle_cast/2, terminate/2, code_change/3, init/1]).
start(Name) -> gen_server:start_link({local, Name}, ?MODULE, [], []).

%%	gen_server:call(Name, Request )调用服务器,但最终回去调用回调模块里的handle_call(Request,From,State),主要取决于Request参数的值一般包含操作方式和对应参数
stop() -> gen_server:call(?MODULE, stop).
new_account(Who) -> gen_server:call(_Name = ?MODULE, _Request = {new, Who}).
deposit({Who, Amount}) -> gen_server:call(_Name = ?MODULE, _Request = {add, Who, Amount}).
withdraw({Who, Amount}) -> gen_server:call(_Name = ?MODULE, _Request = {remove, Who, Amount}).


%%	gen_server 的回调结构

%%	启动服务器
%%	gen_server:start_link(Name, Mod, InitArgs, Opts)
%%	如果返回{ok, State},就说明我们成功启动了服务器,它的初始状态是State
init([]) -> {ok, est:new(?MODULE, [])}.
%%	新增当前用户到数据库
handle_call({new, Who} = _Request, _From, Tab) ->
	Reply = case ets:lookup(Tab, Who) of
						[] -> ets:insert(Tab, {Who, 0});
						[_] -> {Who, already_exist}
					end,
	{reply, Reply, Tab};
%%	存钱
handle_call({add, Who, X}, _From, Tab) ->
	Reply = case ets:lookup(Tab, Who) of
						[] -> not_exist;
						[{Who, Balance}] ->
							NewBalance = Balance + X,
							ets:insert(Tab, {who, NewBalance}),
							{thanks, Who, your_balance_is, NewBalance}
					end,
	{reply, Reply, Tab};
%%	取钱
handle_call({remove, Who, X}, _From, Tab)
	->
	Reply = case ets:lookup(Tab, Who) of
						[] -> not_exist;
						[{Who, Balance}] when X =< Balance ->
							NewBalance = Balance - X,
							ets:insert(Tab, {who, NewBalance}),
							{thanks, Who, your_balance_is, NewBalance};
						[{Who, Balance}] ->
							{sorry, Who, you_only_have, Balance, in_the_bank}
					end,
	{reply, Reply, Tab};
%%	关闭银行
handle_call(stop, _From, Tab) ->
	{stop, normal, stopped, Tab}.
%%	gen_server:cast(Name, Msg)则实现了一个播发(cast),也就是没有返回值的调用(实际上就是一个消息,但习惯上称它为播发来与远程过程调用相区分)
%%	对应的回调方法是handle_cast
handle_cast(_Msg, State) -> {noreply, State}.
%%	回调函数handle_info(Info, State)被用来处理发给服务器的自发性消息。自发性消息是
%%	一切未经显式调用gen_server:call或gen_server:cast而到达服务器的消息
handle_info(_Info, State) -> {noreply, State}.
%%	服务器会因为许多原因而终止。某个以handle_开头的函数也许会返回一个{stop, Reason,NewState},
%%	服务器也可能崩溃并生成{'EXIT', reason}。在所有这些情况下,无论它们是怎样发生的,都会调用terminate(Reason, NewState)。
terminate(_Reason, _State) -> ok.
%%	你可以在服务器运行时动态更改它的状态。这个回调函数会在系统执行软件升级时由版本处理子系统调用。
code_change(_OldVsn, State, _Extra) -> {ok, State}.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值