为了演示需要,我们将前面几节中 messager 程序分布到五个文件中:
mess_config.hrl
配置所需数据头文件
mess_interface.hrl
客户端与 messager 之间的接口定义
user_interface.erl
用户接口函数
mess_client.erl
messager 系统客户端的函数
mess_server.erl
messager 服务端的函数
除了完成上述工作外,我们使用记录重新定义了 shell 、客户端以及服务端的消息格式。此外,我们还引入了下面这些宏:
%%%----FILE mess_config.hrl---- |
%%% Configure the location of the server node, |
-define(server_node, messenger@super). |
%%%----END FILE---- |
%%%----FILE mess_interface.hrl---- |
%%%Message interface between client and server and client shell for |
%%% messenger program |
%%%Messages from Client to server received in server/1 function. |
-record(logon,{client_pid, username}). |
-record(message,{client_pid, to_name, message}). |
%%% {'EXIT', ClientPid, Reason} (client terminated or unreachable. |
%%% Messages from Server to Client, received in await_result/0 function |
-record(abort_client,{message}). |
%%% Messages are: user_exists_at_other_node, |
%%% you_are_not_logged_on |
-record(server_reply,{message}). |
%%% Messages are: logged_on |
%%% receiver_not_found |
%%% sent (Message has been sent (no guarantee) |
%%% Messages from Server to Client received in client/1 function |
-record(message_from,{from_name, message}). |
%%% Messages from shell to Client received in client/1 function |
%%% spawn(mess_client, client, [server_node(), Name]) |
-record(message_to,{to_name, message}). |
%%% logoff |
%%%----END FILE---- |
%%%----FILE mess_interface.hrl---- |
%%% Message interface between client and server and client shell for |
%%% messenger program |
%%%Messages from Client to server received in server/1 function. |
-record(logon,{client_pid, username}). |
-record(message,{client_pid, to_name, message}). |
%%% {'EXIT', ClientPid, Reason} (client terminated or unreachable. |
%%% Messages from Server to Client, received in await_result/0 function |
-record(abort_client,{message}). |
%%% Messages are: user_exists_at_other_node, |
%%% you_are_not_logged_on |
-record(server_reply,{message}). |
%%% Messages are: logged_on |
%%% receiver_not_found |
%%% sent (Message has been sent (no guarantee) |
%%% Messages from Server to Client received in client/1 function |
-record(message_from,{from_name, message}). |
%%% Messages from shell to Client received in client/1 function |
%%% spawn(mess_client, client, [server_node(), Name]) |
-record(message_to,{to_name, message}). |
%%% logoff |
%%%----END FILE---- |
%%%----FILE mess_client.erl---- |
%%% The client process which runs on each user node |
-module(mess_client). |
-export([client/2]). |
-include("mess_interface.hrl"). |
client(Server_Node, Name) -> |
{messenger, Server_Node} ! #logon{client_pid=self(), username=Name}, |
await_result(), |
client(Server_Node). |
client(Server_Node) -> |
receive |
logoff -> |
exit(normal); |
#message_to{to_name=ToName, message=Message} -> |
{messenger, Server_Node} ! |
#message{client_pid=self(), to_name=ToName, message=Message}, |
await_result(); |
{message_from, FromName, Message} -> |
io:format("Message from ~p: ~p~n", [FromName, Message]) |
end, |
client(Server_Node). |
%%% wait for a response from the server |
await_result() -> |
receive |
#abort_client{message=Why} -> |
io:format("~p~n", [Why]), |
exit(normal); |
#server_reply{message=What} -> |
io:format("~p~n", [What]) |
after 5000 -> |
io:format("No response from server~n", []), |
exit(timeout) |
end. |
%%%----END FILE--- |
%%%----FILE mess_server.erl---- |
%%% This is the server process of the messenger service |
-module(mess_server). |
-export([start_server/0, server/0]). |
-include("mess_interface.hrl"). |
server() -> |
process_flag(trap_exit, true), |
server([]). |
%%% the user list has the format [{ClientPid1, Name1},{ClientPid22, Name2},...] |
server(User_List) -> |
io:format("User list = ~p~n", [User_List]), |
receive |
#logon{client_pid=From, username=Name} -> |
New_User_List = server_logon(From, Name, User_List), |
server(New_User_List); |
{'EXIT', From, _} -> |
New_User_List = server_logoff(From, User_List), |
server(New_User_List); |
#message{client_pid=From, to_name=To, message=Message} -> |
server_transfer(From, To, Message, User_List), |
server(User_List) |
end. |
%%% Start the server |
start_server() -> |
register(messenger, spawn(?MODULE, server, [])). |
%%% Server adds a new user to the user list |
server_logon(From, Name, User_List) -> |
%% check if logged on anywhere else |
case lists:keymember(Name, 2, User_List) of |
true -> |
From ! #abort_client{message=user_exists_at_other_node}, |
User_List; |
false -> |
From ! #server_reply{message=logged_on}, |
link(From), |
[{From, Name} | User_List] %add user to the list |
end. |
%%% Server deletes a user from the user list |
server_logoff(From, User_List) -> |
lists:keydelete(From, 1, User_List). |
%%% Server transfers a message between user |
server_transfer(From, To, Message, User_List) -> |
%% check that the user is logged on and who he is |
case lists:keysearch(From, 1, User_List) of |
false -> |
From ! #abort_client{message=you_are_not_logged_on}; |
{value, {_, Name}} -> |
server_transfer(From, Name, To, Message, User_List) |
end. |
%%% If the user exists, send the message |
server_transfer(From, Name, To, Message, User_List) -> |
%% Find the receiver and send the message |
case lists:keysearch(To, 2, User_List) of |
false -> |
From ! #server_reply{message=receiver_not_found}; |
{value, {ToPid, To}} -> |
ToPid ! #message_from{from_name=Name, message=Message}, |
From ! #server_reply{message=sent} |
end. |
%%%----END FILE--- |