Erlang 程序分布

将大程序分在多个文件中

为了演示需要,我们将前面几节中 messager 程序分布到五个文件中:

  • mess_config.hrl

    配置所需数据头文件

  • mess_interface.hrl

    客户端与 messager 之间的接口定义

  • user_interface.erl

    用户接口函数

  • mess_client.erl

    messager 系统客户端的函数

  • mess_server.erl

    messager 服务端的函数

除了完成上述工作外,我们使用记录重新定义了 shell 、客户端以及服务端的消息格式。此外,我们还引入了下面这些宏:

  1. %%%----FILE mess_config.hrl----
  2. %%% Configure the location of the server node,
  3. -define(server_node, messenger@super).
  4. %%%----END FILE----
  1. %%%----FILE mess_interface.hrl----
  2. %%%Message interface between client and server and client shell for
  3. %%% messenger program
  4. %%%Messages from Client to server received in server/1 function.
  5. -record(logon,{client_pid, username}).
  6. -record(message,{client_pid, to_name, message}).
  7. %%% {'EXIT', ClientPid, Reason} (client terminated or unreachable.
  8. %%% Messages from Server to Client, received in await_result/0 function
  9. -record(abort_client,{message}).
  10. %%% Messages are: user_exists_at_other_node,
  11. %%% you_are_not_logged_on
  12. -record(server_reply,{message}).
  13. %%% Messages are: logged_on
  14. %%% receiver_not_found
  15. %%% sent (Message has been sent (no guarantee)
  16. %%% Messages from Server to Client received in client/1 function
  17. -record(message_from,{from_name, message}).
  18. %%% Messages from shell to Client received in client/1 function
  19. %%% spawn(mess_client, client, [server_node(), Name])
  20. -record(message_to,{to_name, message}).
  21. %%% logoff
  22. %%%----END FILE----
  1. %%%----FILE mess_interface.hrl----
  2. %%% Message interface between client and server and client shell for
  3. %%% messenger program
  4. %%%Messages from Client to server received in server/1 function.
  5. -record(logon,{client_pid, username}).
  6. -record(message,{client_pid, to_name, message}).
  7. %%% {'EXIT', ClientPid, Reason} (client terminated or unreachable.
  8. %%% Messages from Server to Client, received in await_result/0 function
  9. -record(abort_client,{message}).
  10. %%% Messages are: user_exists_at_other_node,
  11. %%% you_are_not_logged_on
  12. -record(server_reply,{message}).
  13. %%% Messages are: logged_on
  14. %%% receiver_not_found
  15. %%% sent (Message has been sent (no guarantee)
  16. %%% Messages from Server to Client received in client/1 function
  17. -record(message_from,{from_name, message}).
  18. %%% Messages from shell to Client received in client/1 function
  19. %%% spawn(mess_client, client, [server_node(), Name])
  20. -record(message_to,{to_name, message}).
  21. %%% logoff
  22. %%%----END FILE----
  1. %%%----FILE mess_client.erl----
  2. %%% The client process which runs on each user node
  3. -module(mess_client).
  4. -export([client/2]).
  5. -include("mess_interface.hrl").
  6. client(Server_Node, Name) ->
  7. {messenger, Server_Node} ! #logon{client_pid=self(), username=Name},
  8. await_result(),
  9. client(Server_Node).
  10. client(Server_Node) ->
  11. receive
  12. logoff ->
  13. exit(normal);
  14. #message_to{to_name=ToName, message=Message} ->
  15. {messenger, Server_Node} !
  16. #message{client_pid=self(), to_name=ToName, message=Message},
  17. await_result();
  18. {message_from, FromName, Message} ->
  19. io:format("Message from ~p: ~p~n", [FromName, Message])
  20. end,
  21. client(Server_Node).
  22. %%% wait for a response from the server
  23. await_result() ->
  24. receive
  25. #abort_client{message=Why} ->
  26. io:format("~p~n", [Why]),
  27. exit(normal);
  28. #server_reply{message=What} ->
  29. io:format("~p~n", [What])
  30. after 5000 ->
  31. io:format("No response from server~n", []),
  32. exit(timeout)
  33. end.
  34. %%%----END FILE---
  1. %%%----FILE mess_server.erl----
  2. %%% This is the server process of the messenger service
  3. -module(mess_server).
  4. -export([start_server/0, server/0]).
  5. -include("mess_interface.hrl").
  6. server() ->
  7. process_flag(trap_exit, true),
  8. server([]).
  9. %%% the user list has the format [{ClientPid1, Name1},{ClientPid22, Name2},...]
  10. server(User_List) ->
  11. io:format("User list = ~p~n", [User_List]),
  12. receive
  13. #logon{client_pid=From, username=Name} ->
  14. New_User_List = server_logon(From, Name, User_List),
  15. server(New_User_List);
  16. {'EXIT', From, _} ->
  17. New_User_List = server_logoff(From, User_List),
  18. server(New_User_List);
  19. #message{client_pid=From, to_name=To, message=Message} ->
  20. server_transfer(From, To, Message, User_List),
  21. server(User_List)
  22. end.
  23. %%% Start the server
  24. start_server() ->
  25. register(messenger, spawn(?MODULE, server, [])).
  26. %%% Server adds a new user to the user list
  27. server_logon(From, Name, User_List) ->
  28. %% check if logged on anywhere else
  29. case lists:keymember(Name, 2, User_List) of
  30. true ->
  31. From ! #abort_client{message=user_exists_at_other_node},
  32. User_List;
  33. false ->
  34. From ! #server_reply{message=logged_on},
  35. link(From),
  36. [{From, Name} | User_List] %add user to the list
  37. end.
  38. %%% Server deletes a user from the user list
  39. server_logoff(From, User_List) ->
  40. lists:keydelete(From, 1, User_List).
  41. %%% Server transfers a message between user
  42. server_transfer(From, To, Message, User_List) ->
  43. %% check that the user is logged on and who he is
  44. case lists:keysearch(From, 1, User_List) of
  45. false ->
  46. From ! #abort_client{message=you_are_not_logged_on};
  47. {value, {_, Name}} ->
  48. server_transfer(From, Name, To, Message, User_List)
  49. end.
  50. %%% If the user exists, send the message
  51. server_transfer(From, Name, To, Message, User_List) ->
  52. %% Find the receiver and send the message
  53. case lists:keysearch(To, 2, User_List) of
  54. false ->
  55. From ! #server_reply{message=receiver_not_found};
  56. {value, {ToPid, To}} ->
  57. ToPid ! #message_from{from_name=Name, message=Message},
  58. From ! #server_reply{message=sent}
  59. end.
  60. %%%----END FILE---