<source id="4vppl"><ins id="4vppl"></ins></source>
<u id="4vppl"><sub id="4vppl"><label id="4vppl"></label></sub></u>
<object id="4vppl"></object>
  • <u id="4vppl"><li id="4vppl"><label id="4vppl"></label></li></u>

    <object id="4vppl"></object>
    <b id="4vppl"><sub id="4vppl"><tr id="4vppl"></tr></sub></b>

      <i id="4vppl"><thead id="4vppl"></thead></i>

      <thead id="4vppl"><li id="4vppl"><label id="4vppl"></label></li></thead>

      當前位置:首頁 > 網站舊欄目 > 學習園地 > 設計軟件教程 > gen_server tasting 之超簡單名稱服務

      gen_server tasting 之超簡單名稱服務
      2010-01-13 23:16:59  作者:  來源:
           年假不能白休,時間不能浪費,看了 erlang 程序設計的 gen_server 章節,為了更好的理解、掌握于是上手寫一個名稱(鍵值)服務器。這個 lzy_name_svc 服務器是基于 otp gen_server 寫成的,在底層鍵值被保存在了 erlang 的進程字典里,并且用于存儲字典的進程是可以替換的,可以通過 lzy_name_svc:start/1 啟動服務時指定,缺省情況保存在“當前” erlang 進程中。閑話少敘,代碼貼上。

       

      Erlang代碼 復制代碼
      1. -module(lzy_name_svc).   
      2.   
      3. -behaviour(gen_server).   
      4.   
      5. -export([init/0, init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).   
      6. -export([start/0, start/1, stop/0, save/2, load/1, load_all/0, remove/1, remove_all/0]).   
      7.   
      8. %% Interface functions.   
      9.   
      10. start() ->   
      11.     gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).   
      12.   
      13. start(Args) ->   
      14.     gen_server:start_link({local, ?MODULE}, ?MODULE, Args, []).   
      15.   
      16. stop() ->   
      17.     gen_server:call(?MODULE, stop).   
      18.   
      19.   
      20. %% @spec save(Key, Value) -> OldValue.   
      21. save(Key, Value) ->   
      22.     gen_server:call(?MODULE, {save, Key, Value}).   
      23.   
      24. %% @spec load(Key) -> Value.   
      25. load(Key) ->   
      26.     gen_server:call(?MODULE, {load, Key}).   
      27.   
      28. %% @spec load_all() -> [{Key, Value}].   
      29. load_all() ->   
      30.     gen_server:call(?MODULE, {load_all}).   
      31.   
      32. %% @spec remove(Key) -> Value.   
      33. remove(Key) ->   
      34.     gen_server:call(?MODULE, {remove, Key}).   
      35.   
      36. %% @spec remove_all() -> [{Key, Value}].   
      37. remove_all() ->   
      38.     gen_server:call(?MODULE, {remove_all}).   
      39.   
      40.   
      41. %%  Callback functions.   
      42.   
      43. init([]) ->   
      44.     {ok, local};   
      45.   
      46. init([{isolation, NameServer}]) ->   
      47.     {ok, {isolation, NameServer}}.   
      48.   
      49. handle_call({save, Key, Value}, _From, NameServer) ->   
      50.     {reply, do_save(Key, Value, NameServer), NameServer};   
      51.   
      52. handle_call({load, Key}, _From, NameServer) ->   
      53.     {reply, do_load(Key, NameServer), NameServer};   
      54.   
      55. handle_call({load_all}, _From, NameServer) ->   
      56.     {reply, do_load_all(NameServer), NameServer};   
      57.   
      58. handle_call({remove, Key}, _From, NameServer) ->   
      59.     {reply, do_remove(Key, NameServer), NameServer};   
      60.   
      61. handle_call({remove_all}, _From, NameServer) ->   
      62.     {reply, do_remove_all(NameServer), NameServer};   
      63.   
      64. handle_call({stop}, _From, NameServer) ->   
      65.     {stop, normal, stopped, NameServer}.   
      66.   
      67. %% Default implement.   
      68.   
      69. handle_cast(_Msg, State) ->   
      70.     {noreply, State}.   
      71.        
      72. handle_info(_Info, State) ->   
      73.     {noreply, State}.   
      74.   
      75. terminate(_Reason, _State) ->   
      76.     ok.   
      77.   
      78. code_change(_OldVsn, State, _Extra) ->   
      79.     {ok, State}.   
      80.   
      81. %% Private functions.   
      82.   
      83. do_save(Key, Value, {isolation, NameServer}) ->   
      84.     NameServer ! {self(), save, Key, Value},   
      85.     receive   
      86.         Msg -> Msg   
      87.     end;   
      88.   
      89. do_save(Key, Value, _) ->   
      90.     erlang:put(Key, Value).   
      91.   
      92. do_load(Key, {isolation, NameServer}) ->   
      93.     NameServer ! {self(), load, Key},   
      94.     receive   
      95.         Msg -> Msg   
      96.     end;   
      97.   
      98. do_load(Key, _) ->   
      99.     erlang:get(Key).   
      100.   
      101. do_load_all({isolation, NameServer}) ->   
      102.     NameServer ! {self(), load_all},   
      103.     receive   
      104.         Msg -> Msg   
      105.     end;   
      106.   
      107. do_load_all(_) ->   
      108.     erlang:get().   
      109.   
      110. do_remove(Key, {isolation, NameServer}) ->   
      111.     NameServer ! {self(), remove, Key},   
      112.     receive   
      113.         Msg -> Msg   
      114.     end;   
      115.   
      116. do_remove(Key, _) ->   
      117.     erlang:erase(Key).   
      118.   
      119. do_remove_all({isolation, NameServer}) ->   
      120.     NameServer ! {self(), remove_all},   
      121.     receive   
      122.         Msg -> Msg   
      123.     end;   
      124.   
      125. do_remove_all(_) ->   
      126.     erlang:erase().  

       

      上面這段代碼就是 lzy_name_svc 名稱服務了,有些地方寫得有點冗余,呵呵。

       

                為了能夠替換字典進程來測試驗證名稱服務功能,還寫了一個超簡單的 foo_svc 服務,用來和 lzy_name_svc 通信完成進程字典存取。

       

      Erlang代碼 復制代碼
      1. -module(foo_svc).   
      2.   
      3. -export([start/0, load_all/0, server_pid/0]).   
      4.   
      5. start() ->   
      6.     register(fs, spawn(fun() -> loop() end)).   
      7.   
      8. load_all() ->   
      9.     fs !  {self(), load_all},   
      10.     receive   
      11.         Msg -> Msg   
      12.     end.   
      13.        
      14. server_pid() ->   
      15.     fs ! { self(), server_pid},   
      16.     receive   
      17.         Msg -> Msg   
      18.     end.   
      19.        
      20. loop() ->   
      21.     receive   
      22.         {From, save, Key, Value} ->   
      23.             From ! erlang:put(Key, Value),   
      24.             loop();   
      25.         {From, load, Key} ->   
      26.             From ! erlang:get(Key),   
      27.             loop();   
      28.         {From, load_all} ->   
      29.             From ! erlang:get(),   
      30.             loop();   
      31.         {From, remove, Key} ->   
      32.             From ! erlang:erase(Key),   
      33.             loop();   
      34.         {From, remove_all} ->   
      35.             From ! erlang:erase(),   
      36.             loop();   
      37.         {From, server_pid} ->   
      38.             From ! self(),   
      39.             loop()   
      40.     end.  

       

                下面的代碼就是創建和調用服務的相關代碼了,一起貼上來。第一段是以缺省方式啟動了 lzy_name_svc 服務,并向存取 abc -> 123 名稱。

       

      Erlang代碼 復制代碼
      1. C:\Program Files\erl5.6.4\usr>..\bin\erl -sname server   
      2. Eshell V5.6.4  (abort with ^G)   
      3. (server@lzy)1> c(lzy_name_svc).   
      4. {ok,lzy_name_svc}   
      5. (server@lzy)2> c(foo_svc.erl).   
      6. {ok,foo_svc}   
      7. (server@lzy)3> lzy_name_svc:start().   
      8. {ok,<0.47.0>}   
      9. (server@lzy)4> lzy_name_svc:save(abc, 123).   
      10. undefined   
      11. (server@lzy)5> lzy_name_svc:load(abc).   
      12. 123  
      13. (server@lzy)6> lzy_name_svc:load(efg).   
      14. undefined   
      15. (server@lzy)7> lzy_name_svc:load_all().   
      16. [{abc,123},   
      17.  {'$ancestors',[<0.35.0>]},   
      18.  {'$initial_call',{gen,init_it,   
      19.                        [gen_server,<0.35.0>,<0.35.0>,   
      20.                         {local,lzy_name_svc},   
      21.                         lzy_name_svc,[],[]]}}]   
      22. (server@lzy)8> lzy_name_svc:remove(abc).   
      23. 123  
      24. (server@lzy)9> lzy_name_svc:load(abc).   
      25. undefined  

       

      下面這段是啟動 foo_svc 服務,用它創建的進程來專門存儲名稱數據,是通過 lzy_name_svc:start/1 傳入的 PID。

       

      Erlang代碼 復制代碼
      1. C:\Program Files\erl5.6.4\usr>..\bin\erl -sname server   
      2. Eshell V5.6.4  (abort with ^G)   
      3. (server@lzy)1> foo_svc:start().   
      4. true   
      5. (server@lzy)2> NameSvcPid = foo_svc:server_pid().   
      6. <0.37.0>   
      7. (server@lzy)3> lzy_name_svc:start([{isolation, NameSvcPid}]).   
      8. {ok,<0.40.0>}   
      9. (server@lzy)4> lzy_name_svc:save(abc, 123).   
      10. undefined   
      11. (server@lzy)5> lzy_name_svc:load(abc).   
      12. 123  
      13. (server@lzy)6> foo_svc:load_all().   
      14. [{abc,123}]   
      15. (server@lzy)7> lzy_name_svc:remove_all().   
      16. [{abc,123}]   
      17. (server@lzy)8> foo_svc:load_all().   
      18. []  

       

                上邊的兩段都是在同一機器上的同一 erlang 節點上完成服務調用的,下面這段代碼是 lzy_name_svc 服務基于上邊狀態時,在同一機器的另外了個 erlang 節點上通過 rpc 庫完成服務調用的。

       

      Erlang代碼 復制代碼
      1. C:\Program Files\erl5.6.4\usr>..\bin\erl -sname client1   
      2. Eshell V5.6.4  (abort with ^G)   
      3. (client1@lzy)1> rpc:call(server@lzy, lzy_name_svc, save, [abc, 123]).   
      4. undefined   
      5. (client1@lzy)2> rpc:call(server@lzy, foo_svc, load_all, []).   
      6. [{abc,123}]  
       

      呵呵,挺入門的,就當做為學習過程的記錄吧。看好 erlang。

       

                在學習的過程中,有一個事情比較不解,就是對于 字典進程的 “熱替換” 我想本應該是可以通過 gen_server behaviour 用于“熱代碼替換”的 code_change 方法完成的,但試了幾次都達不到目的,服務倒是跑的正常,可是字典進程就是不能熱替換,code_change 正常返回,可是名稱數據卻還是原有字典進程的。測試驗證代碼如下:

       

      Erlang代碼 復制代碼
      1. C:\Program Files\erl5.6.4\usr>..\bin\erl -sname server   
      2. Eshell V5.6.4  (abort with ^G)   
      3. (server@lzy)1> lzy_name_svc:start().   
      4. {ok,<0.37.0>}   
      5. (server@lzy)2> lzy_name_svc:save(abc, 123).   
      6. undefined   
      7. (server@lzy)3> lzy_name_svc:load_all().   
      8. [{abc,123},   
      9.  {'$ancestors',[<0.35.0>]},   
      10.  {'$initial_call',{gen,init_it,   
      11.                        [gen_server,<0.35.0>,<0.35.0>,   
      12.                         {local,lzy_name_svc},   
      13.                         lzy_name_svc,[],[]]}}]   
      14. (server@lzy)4> foo_svc:start().   
      15. true   
      16. (server@lzy)5> NameSvcPid = foo_svc:server_pid().   
      17. <0.41.0>   
      18. (server@lzy)6> foo_svc:load_all().   
      19. []   
      20. (server@lzy)7> lzy_name_svc:code_change(foo, NameSvcPid, foo).   
      21. {ok,<0.41.0>}   
      22. (server@lzy)8> lzy_name_svc:load_all().   
      23. [{abc,123},   
      24.  {'$ancestors',[<0.35.0>]},   
      25.  {'$initial_call',{gen,init_it,   
      26.                        [gen_server,<0.35.0>,<0.35.0>,   
      27.                         {local,lzy_name_svc},   
      28.                         lzy_name_svc,[],[]]}}]  

       

      還請哪位 erlang guru 指點~

       

      // 2009.02.07 22:52 添加 ////

       

      這里提供了該名稱服務的新迭代版本。

      gen_server tasting 之超簡單名稱服務(續)

       

      添加了如下功能:

       

      1. 使用 otp 監控樹保證服務可靠性。
      2. 添加日志功能,記錄警告事件。
      3. 將名稱服務打包為 application。
      4. 開放 socket 服務,使用 vsns://verb /param 自定義協議對外提供訪問支持。

       


      安徽新華電腦學校專業職業規劃師為你提供更多幫助【在線咨詢
      国产午夜福三级在线播放_亚洲精品成a人片在线观看_亚洲自慰一区二区三区_久久棈精品久久久久久噜噜
      <source id="4vppl"><ins id="4vppl"></ins></source>
      <u id="4vppl"><sub id="4vppl"><label id="4vppl"></label></sub></u>
      <object id="4vppl"></object>
    1. <u id="4vppl"><li id="4vppl"><label id="4vppl"></label></li></u>

      <object id="4vppl"></object>
      <b id="4vppl"><sub id="4vppl"><tr id="4vppl"></tr></sub></b>

        <i id="4vppl"><thead id="4vppl"></thead></i>

        <thead id="4vppl"><li id="4vppl"><label id="4vppl"></label></li></thead>
        亚洲AV永久一区二区三区蜜桃 | 午夜性色福利在线视频网站 | 日韩有码在线观看 | 亚洲一级精品在线观看 | 中文字幕不卡二区亚洲 | 中文字幕免费精品视频一级 |