歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Erlang服務器編程思想和實現

Erlang服務器編程思想和實現

日期:2017/3/1 10:27:23   编辑:Linux編程

下面會寫到4個服務器程序,他們以server1,server2...這樣的方式命名,好戲即將開始深吸一口氣,go!!

更多關於Erlang的詳細信息,或者下載地址請點這裡

1.server1 原始服務器程序

server1.erl

  1. -module(server1).
  2. -export([start/2, rpc/2]).
  3. start(Name, Mod) ->
  4. register(Name, spawn(fun() -> loop(Name, Mod, Mod:init()) end)).
  5. rpc(Name, Request) ->
  6. Name ! {self(), Request},
  7. receive
  8. {Name, Response} -> Response
  9. end.
  10. loop(Name, Mod, State) ->
  11. receive
  12. {From, Request} ->
  13. {Response, State1} = Mod:handle(Request, State),
  14. From ! {Name, Response},
  15. loop(Name, Mod, State1)
  16. end.

這段代碼是erlang的標准服務器程序,下面寫一個回調函數來運行測試。

name_server.erl

  1. -module(name_server).
  2. -export([init/0, add/2, whereis/1, handle/2]).
  3. -import(server1, [rpc/2]).
  4. %% client routines
  5. add(Name, Place) -> rpc(name_server, {add, Name, Place}).
  6. whereis(Name) -> rpc(name_server, {whereis, Name}).
  7. %% callback routines
  8. init() -> dict:new().
  9. handle({add, Name, Place}, Dict) -> {ok, dict:store(Name, Place, Dict)};
  10. handle({whereis, Name}, Dict) -> {dict:find(Name, Dict), Dict}.

首先看後面的代碼1.他負責回調服務器程序,處理其他進程發貨來的請求2.相當於定義接口。

如下運行程序:

  1. erlc *.erl
  1. Eshell V5.6.5 (abort with ^G)
  2. 1> server1:start(name_server, name_server).
  3. true
  4. 2> nameserver:add("lengzijian","go to school").
  5. ** exception error: undefined function nameserver:add/2
  6. 3> name_server:add("lengzijian","go to school").
  7. ok
  8. 4> name_server:whereis("lengzijian").
  9. {ok,"go to school"}
  10. 5>

如果讀者細心可以發現,這段代碼裡面並沒有spawn這樣的創建進程的命令,不錯,這個服務器程序完全是順序性代碼,也許有人質疑這樣做的意義,不要急這才剛剛開始

2.server2:支持事務的服務器程序

接下來要向大家展示的是,當服務器宕機,客戶端回或得到異常,然後做相應的處理。

server2.erl

  1. -module(server2).
  2. -export([start/2, rpc/2]).
  3. start(Name, Mod) ->
  4. register(Name, spawn(fun() -> loop(Name,Mod,Mod:init()) end)).
  5. rpc(Name, Request) ->
  6. Name ! {self(), Request},
  7. receive
  8. {Name, crash} -> exit(rpc);
  9. {Name, ok, Response} -> Response
  10. end.
  11. loop(Name, Mod, OldState) ->
  12. receive
  13. {From, Request} ->
  14. try Mod:handle(Request, OldState) of
  15. {Response, NewState} ->
  16. From ! {Name, ok, Response},
  17. loop(Name, Mod, NewState)
  18. catch
  19. _:Why ->
  20. log_the_error(Name, Request, Why),
  21. %% send a message to cause the client to crash
  22. From ! {Name, crash},
  23. %% loop with the *original* state
  24. loop(Name, Mod, OldState)
  25. end
  26. end.
  27. log_the_error(Name, Request, Why) ->
  28. io:format("Server ~p request ~p ~n"
  29. "caused exception ~p~n",
  30. [Name, Request, Why]).

想對於之前的版本,多了注冊函數和創建進程函數,可以理解的認為是增加了並行操作,但是我之前做過一些小項目而言,erlang的進程的確有他特殊的地方,這裡會在之後的文章詳細講解,這段代碼實際上是提供了“事務機制”,在handler發生異常時,回調用loop(Name, Mod, OldState)在之前的狀態下進行循環,否則會在新的狀態下進行運行

流程是怎樣的呢:當服務端宕機,服務器會給客戶端發送crash消息,說明服務器異常,然後客戶端接收到消息後,可以做相應處理(在我們的項目中用到的是重連,例子中是退出),然後調用loop並帶入變量OldState說明本次服務處理異常,同時不影響其他連接到服務器的客戶端。

要測試的話,與server1完全相同只需要改變import時改為server2即可。

Copyright © Linux教程網 All Rights Reserved