加入收藏 | 设为首页 | 会员中心 | 我要投稿 南通站长网 (https://www.0513zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 教程 > 正文

Erlang服务器编程思想和达成

发布时间:2021-11-23 18:16:15 所属栏目:教程 来源:互联网
导读:下面会写到4个服务器程序,他们以server1,server2...这样的方式命名,好戏即将开始深吸一口气,go!! 更多关于Erlang的详细信息,或者下载地址请点这里 1.server1 原始服务器程序 server1.erl -module(server1). -export([start/2, rpc/2]). start(Name, M

下面会写到4个服务器程序,他们以server1,server2...这样的方式命名,好戏即将开始深吸一口气,go!!
 
更多关于Erlang的详细信息,或者下载地址请点这里
 
1.server1 原始服务器程序
 
server1.erl
 
-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(Request, State),  
            From ! {Name, Response},  
            loop(Name, Mod, State1)  
    end.
这段代码是erlang的标准服务器程序,下面写一个回调函数来运行测试。
 
name_server.erl
 
-module(name_server).  
-export([init/0, add/2, whereis/1, handle/2]).  
-import(server1, [rpc/2]).  
  
%% client routines  
add(Name, Place) -> rpc(name_server, {add, Name, Place}).  
whereis(Name)    -> rpc(name_server, {whereis, Name}).  
  
%% callback routines  
init() -> dict:new().  
  
handle({add, Name, Place}, Dict) -> {ok, dict:store(Name, Place, Dict)};  
handle({whereis, Name}, Dict)    -> {dict:find(Name, Dict), Dict}.
首先看后面的代码1.他负责回调服务器程序,处理其他进程发货来的请求2.相当于定义接口。
 
如下运行程序:
 
erlc *.erl   
Eshell V5.6.5  (abort with ^G)  
1> server1:start(name_server, name_server).  
true  
2> nameserver:add("lengzijian","go to school").  
** exception error: undefined function nameserver:add/2  
3> name_server:add("lengzijian","go to school").  
ok  
4> name_server:whereis("lengzijian").  
{ok,"go to school"}  
5>   
如果读者细心可以发现,这段代码里面并没有spawn这样的创建进程的命令,不错,这个服务器程序完全是顺序性代码,也许有人质疑这样做的意义,不要急这才刚刚开始
 
2.server2:支持事务的服务器程序
 
接下来要向大家展示的是,当服务器宕机,客户端回或得到异常,然后做相应的处理。
 
server2.erl
 
-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(Request, OldState) of  
        {Response, NewState} ->  
            From ! {Name, ok, Response},  
            loop(Name, Mod, NewState)  
        catch  
        _:Why ->  
            log_the_error(Name, Request, Why),  
            %% send a message to cause the client to crash  
            From ! {Name, crash},  
            %% loop with the *original* state  
            loop(Name, Mod, OldState)  
        end  
    end.  
  
log_the_error(Name, Request, Why) ->  
    io:format("Server ~p request ~p ~n"  
          "caused exception ~p~n",   
          [Name, Request, Why]).    
想对于之前的版本,多了注册函数和创建进程函数,可以理解的认为是增加了并行操作,但是我之前做过一些小项目而言,erlang的进程的确有他特殊的地方,这里会在之后的文章详细讲解,这段代码实际上是提供了“事务机制”,在handler发生异常时,回调用loop(Name, Mod, OldState)在之前的状态下进行循环,否则会在新的状态下进行运行
 
流程是怎样的呢:当服务端宕机,服务器会给客户端发送crash消息,说明服务器异常,然后客户端接收到消息后,可以做相应处理(在我们的项目中用到的是重连,例子中是退出),然后调用loop并带入变量OldState说明本次服务处理异常,同时不影响其他连接到服务器的客户端。
 
要测试的话,与server1完全相同只需要改变import时改为server2即可。

(编辑:南通站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读