- %%% Message passing utility.
-
%%% User interface:
-
%%% logon(Name)
-
%%% One user at a time can log in from each Erlang node in the
-
%%% system messenger: and choose a suitable Name. If the Name
-
%%% is already logged in at another node or if someone else is
-
%%% already logged in at the same node, login will be rejected
-
%%% with a suitable error message.
-
%%% logoff()
-
%%% Logs off anybody at at node
-
%%% message(ToName, Message)
-
%%% sends Message to ToName. Error messages if the user of this
-
%%% function is not logged on or if ToName is not logged on at
-
%%% any node.
-
%%%
-
%%% One node in the network of Erlang nodes runs a server which maintains
-
%%% data about the logged on users. The server is registered as "messenger"
-
%%% Each node where there is a user logged on runs a client process registered
-
%%% as "mess_client"
-
%%%
-
%%% Protocol between the client processes and the server
-
%%% ----------------------------------------------------
-
%%%
-
%%% To server: {ClientPid, logon, UserName}
-
%%% Reply {messenger, stop, user_exists_at_other_node} stops the client
-
%%% Reply {messenger, logged_on} logon was successful
-
%%%
-
%%% To server: {ClientPid, logoff}
-
%%% Reply: {messenger, logged_off}
-
%%%
-
%%% To server: {ClientPid, logoff}
-
%%% Reply: no reply
-
%%%
-
%%% To server: {ClientPid, message_to, ToName, Message} send a message
-
%%% Reply: {messenger, stop, you_are_not_logged_on} stops the client
-
%%% Reply: {messenger, receiver_not_found} no user with this name logged on
-
%%% Reply: {messenger, sent} Message has been sent (but no guarantee)
-
%%%
-
%%% To client: {message_from, Name, Message},
-
%%%
-
%%% Protocol between the "commands" and the client
-
%%% ----------------------------------------------
-
%%%
-
%%% Started: messenger:client(Server_Node, Name)
-
%%% To client: logoff
-
%%% To client: {message_to, ToName, Message}
-
%%%
-
%%% Configuration: change the server_node() function to return the
-
%%% name of the node where the messenger server runs
-
-
-module(messenger).
-
-export([start_server/0, server/1, logon/1, logoff/0, message/2, client/2]).
-
-
%%% Change the function below to return the name of the node where the
-
%%% messenger server runs
-
server_node() ->
-
messenger@Lizhuohua.
-
-
%%% This is the server process for the "messenger"
-
%%% the user list has the format [{ClientPid1, Name1},{ClientPid22, Name2},...]
-
server(User_List) ->
-
%%% 我是服务器的消息处理的地方,等待消息中~~~
-
receive
-
{From, logon, Name} -> %%%咦,有客户来登陆了
-
io:format("4~n"),
-
New_User_List = server_logon(From, Name, User_List), %%%我是server,我需要记录所有的客户,调用server_logon来做这个事情吧
-
io:format("5~n"),
-
server(New_User_List);
-
{From, logoff} -> %%%哟, 有客户要走了。。。
-
New_User_List = server_logoff(From, User_List), %%%一路走好啊,我Server得把你从我得客户列表里删除掉。。。
-
server(New_User_List);
-
{From, message_to, To, Message} -> %%%咦,有客户想聊天?恩,从From这个pid的客户发过来的,
-
%%%我得用我Server的server_transfer(From, To, Message, User_List)函数来转发一下。
-
server_transfer(From, To, Message, User_List),
-
io:format("list is now: ~p~n", [User_List]),
-
server(User_List)
-
end.
-
-
%%% Start the server
-
start_server() ->
-
%%% 我是服务器,启动啦,创建了一个进程,去server(User_List)找我吧
-
register(messenger, spawn(messenger, 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 %%%我是server,对了,我需要先看看已经记录的客户列表里有没有这个要登陆的新客户,
-
%%%每个客户记录的格式用一个Tuple记录{客户的pid,客户的名字},我按名字查找每个Tuple好了,
-
%%%客户的名字在Tuple里的所以是2(从1开始)
-
true -> %%%咦,这个客户已经在我的记录里了
-
From ! {messenger, stop, user_exists_at_other_node}, %那就拒绝他再次登陆吧,发给他一个stop的消息给他,内容是user_exists_at_other_node
-
User_List;
-
false ->%%%恩,这个客户不在已有的记录里,那就让他登陆吧。
-
From ! {messenger, logged_on}, %%%发给他一个登陆成功的消息
-
[{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). %%%按照客户的pid在客户列表里查找,找到就删除吧 ,
-
%%%每个客户记录的格式用一个Tuple记录{客户的pid,客户的名字},我这次按pid查找每个Tuple好了,
-
%%%客户的pid在Tuple里的索引是1(从1开始)
-
-
-
%%% 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 ! {messenger, stop, you_are_not_logged_on};
-
{value, {From, Name}} -> %%%keyserver函数返回的结果就是{value, Tuple},而这个Tuple又是由{From, 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 ! {messenger, receiver_not_found};
-
{value, {ToPid, To}} ->
-
ToPid ! {message_from, Name, Message}, %%%终于可以给目的客户发消息了,恩,得把发送人告诉目的客户是谁发给他的
-
From ! {messenger, sent} %%%恩,还得给发送消息的客户一个回复,他还等着呢。。
-
end.
-
-
-
%%% User Commands
-
logon(Name) -> %%%我是客户端,我来登陆啦
-
case whereis(mess_client) of %%%找找我自己是不是已经存在
-
undefined -> %%%不存在
-
register(mess_client, %%%把自己注册为mess_client, 创建进程,去client(Server_Node, Name)看我的后续吧
-
spawn(messenger, client, [server_node(), Name]));
-
_ -> already_logged_on
-
end.
-
-
logoff() -> %%%没意思,我不想处于登陆状态了,我要下线了,88各位。
-
mess_client ! logoff. %%给自己发了一个logoff的消息
-
-
message(ToName, Message) -> %%我是客户,我想跟别人聊聊天,用这个函数吧, ToName是我的聊天对象
-
case whereis(mess_client) of % Test if the client is running
-
undefined ->
-
not_logged_on;
-
_ -> mess_client ! {message_to, ToName, Message}, %%先给我自己一个消息,我要和别人聊天了, 进入client(Server_Node)的{message_to, ToName, Message}部分
-
ok
-
end.
-
-
-
%%% The client process which runs on each server node
-
client(Server_Node, Name) ->
-
{messenger, Server_Node} ! {self(), logon, Name}, %%%我需要让Server知道我来登陆了,所以给Server发个logon的消息
-
%%%把我自己的pid和Name作为参数发给Server, 下面看server(User_List)函数
-
await_result(), %%%恩。。发完了,我就用这个函数等待Server给我的返回值了
-
client(Server_Node). %%% 恩登陆成功,我进入我自己的消息世界喽 Client(Server_Node),等着Server给我发各种消息了
-
-
client(Server_Node) ->
-
receive %%%我在等待Server给我发各种消息。。。。。~z~z~z
-
logoff ->
-
io:format("8~n"),
-
{messenger, Server_Node} ! {self(), logoff}, %%%唉,还是得让Server知道我走了,给Server发个消息吧
-
exit(normal);
-
{message_to, ToName, Message} ->
-
{messenger, Server_Node} ! {self(), message_to, ToName, Message}, %%%想和别人聊天,消息还得通过Server中转,麻烦,先给Server发个消息吧
-
await_result(); %%%我客户在这等结果了
-
{message_from, FromName, Message} -> %%%咦,Server给我发消息了,原来是有别的客户跟我说话呢。
-
io:format("Message from ~p: ~p~n", [FromName, Message])
-
end,
-
client(Server_Node).
-
-
%%% wait for a response from the server
-
await_result() ->
-
receive
-
{messenger, stop, Why} -> % Stop the client 呀,我被Server拒绝了,原因在Why里。。。 比如重复登陆被拒绝时。
-
io:format("~p~n", [Why]),
-
exit(normal); %%%被Server拒绝了还有啥脸面存活于世,我自杀算了。。
-
{messenger, What} -> % Normal response 恩,Server返回消息了,比如返回logon_on正常登陆的消息, 比如Server发送聊天消息后,告诉启动聊天的客户,消息已经sent
-
io:format("6~n"),
-
io:format("~p~n", [What])
-
end.
运行:
创建3个节点, windows上打开3个cmd,每个分别运行
erl.exe -sname messenger 生成messenger@hostname节点
erl.exe -sname node1 生成node1@hostname节点
erl.exe -sname node2 生成node2@hostname节点
然后在messenger@hostname节点上运行:
messenger:start_server().
之后在node1@hostname节点上运行:
messenger:logon(node1).
之后再node2@hostname节点上运行:
messenger:logon(node2).
可以启动聊天,在node1@hostname节点上运行:
messenger:message(node2, "hello")
最后是logoff,在node1@hostname节点上运行:
messenger:logoff()
阅读(1028) | 评论(0) | 转发(0) |