【问题标题】:Erlang - use of lists when the size is consistently changing over timeErlang - 当大小随时间不断变化时使用列表
【发布时间】:2017-04-01 11:52:59
【问题描述】:

我是 Erlang 的新手,我正在通过使用纯 Erlang 构建一个非常小的聊天程序来学习。

我希望客户端能够连接到服务器,然后相互发送消息。但这一切都是在本地机器上完成的,而不是为了学习而通过网络完成的。

我有一个连接到服务器的所有客户端的列表。

如果客户端 A 向客户端 B 发送消息,我会在客户端 A 的终端中获得所需的输出,但我不知道如何从客户端 A 获取消息以显示在客户端 B 的终端上。

或者我必须为每个客户端设置自己的迷你服务器

-module(server).
-export([start/0]).
-export([server/1]).
-export([connect/0]).
-export([sendMessage/2]).

%%
%% The Server 
%%
start() ->
    EmptyList = [],
    Pid = spawn(server, server, [EmptyList]),
    register(chatServe, Pid).

server(ListOfClients) ->
    receive
        {Client, connect} ->
            Client ! {chatServe, connected},
            List = clientList(ListOfClients, Client),
            server(List);

        {Client, message, MessageBody} ->
            List = ListOfClients,
            lists:foreach(fun(X) -> X ! {chatServe, new_message, MessageBody} end, List),
            Client ! {chatServe, received},
            server(List)
    end.

%%
%% The client will call rpc:call(server@local, server, connect, [])
%% to connect
%%
connect() ->
    chatServe ! {self(), connect},
    receive
        {chatServe, connected} -> connected
    end.

%%
%% The send message method takes two args
%%
%%
sendMessage(SendTo, MessageBody) ->
    chatServe ! {self(), message, MessageBody},
    receive
       {chatServe, received} -> received
    end.

receiveMessage(SendTo, SendFrom, MessageBody) ->
    receive
        {}
    end.


%% 
%% Some helper functions
%%

clientList(List, Client) when length(List) =:= 0 ->
    io:format("List Size = 1~n"),
    [Client];
clientList(List, Client) ->
    io:format("List size = ~p~n", [length(List) + 1]),
    [Client | List].



forwardMessage(SendTo, SentFrom, MessageBody, [H | T]) when H =:= SendTo ->
    SendTo ! {SentFrom, message, MessageBody};
forwardMessage(SendTo, SentFrom, MessageBody, [H | T]) -> 
    forwardMessage(SendTo, SentFrom, MessageBody, T);
forwardMessage(SendTo, SentFrom, MessageBody, []) -> [].

在我正在调用的客户端的终端中 rpc:call(host, mod, function, args).

所以我的问题是如何让客户端 A 通过服务器 C 向客户端 B 发送消息,客户端 A 显示成功,客户端 B 显示已发送的消息?

提前致谢

【问题讨论】:

  • 不是一个答案,但我在这里放了一个与一些 cmets 聊天的例子github.com/pascalchap/minichat
  • @Pascal 感谢您的回复。似乎您为每个客户端使用了一个监听循环。是的,这是有道理的。

标签: erlang ipc erlang-shell


【解决方案1】:

在这个例子中,我的服务器是一个 Erlang 节点,每个客户端也是一个 Erlang 节点。

代码:

-module(test).
-export([server_start/1, client_start/2]).
-export([server_new_message/2, client_new_message/2]).








server_start(ServerName) ->
    {ok, _Pid} = net_kernel:start([ServerName, shortnames]),
    erlang:register(server, erlang:self()),
    io:format("Server '~p' started.~nMessages: ~n ~n", [erlang:node()]), 
    server_loop().






server_loop() ->
    receive
        {msg, Name, Text} ->
            io:format("~p: ~p~n", [Name, Text]),
            Receivers = lists:delete(Name, erlang:nodes()),
            rpc:multicall(Receivers, ?MODULE, client_new_message, [Name, Text]),
            server_loop()
    end.




%% Server runs this function in client's node.
%% 'client' process in client's node will receive this message and print it
client_new_message(Name, Text) ->
    client ! {msg, Name, Text}.





client_start(ServerName, ClientName) ->
    {ok, _Pid} = net_kernel:start([ClientName, shortnames]),
    pong = net_adm:ping(ServerName),
    timer:sleep(1000), % wait for updating erlang:nodes()
    Other = lists:delete(ServerName, erlang:nodes()),
    io:format("Client '~p' connected to server '~p'.~nOnline users: ~p~n", [erlang:node(), ServerName, Other]),
    erlang:register(client, spawn_link(fun print/0)),
    client_loop(ServerName).





print() ->
    receive
        {msg, Name, Text} ->
            io:format("~p: ~p~n", [Name, Text]),
            print()
    end.





client_loop(ServerName) ->
    rpc:call(ServerName, ?MODULE, server_new_message, [erlang:node(), io:get_line(">>> ")]),
    client_loop(ServerName).




%% Clients run this function in server's node
%% 'server' process will receive messages and print them and broadcast them
server_new_message(Name, Text) ->
    server ! {msg, Name, Text}.

运行:

我打开了 3 个 Erlang shell。 在 shell 1 我运行服务器:

p@jahanbakhsh ~/Desktop $ erl
Erlang/OTP 19 [erts-8.2.2] [source-1ca84a4] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V8.2.2  (abort with ^G)
1> test:server_start(local_chat_server).
Server 'local_chat_server@jahanbakhsh' started.
Messages: 

服务器正在等待消息。

在 shell 2 我运行客户端 1:

p@jahanbakhsh ~/Desktop $ erl
Erlang/OTP 19 [erts-8.2.2] [source-1ca84a4] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V8.2.2  (abort with ^G)
1> test:client_start('local_chat_server@jahanbakhsh', client_1).
Client 'client_1@jahanbakhsh' connected to server 'local_chat_server@jahanbakhsh'.
Online users: []
>>> 

现在我可以从这个终端发送消息,但请稍等。 我在 shell 3 中运行客户端 2:

p@jahanbakhsh ~/Desktop $ erl
Erlang/OTP 19 [erts-8.2.2] [source-1ca84a4] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V8.2.2  (abort with ^G)
1> test:client_start('local_chat_server@jahanbakhsh', client_2).
Client 'client_2@jahanbakhsh' connected to server 'local_chat_server@jahanbakhsh'.
Online users: [client_1@jahanbakhsh]
>>>

我从 shell 2 或客户端 1 发送消息(“测试消息”)。
在 shell 1 或服务器中,我有:

client_1@jahanbakhsh: "Test message\n" - sent to [client_2@jahanbakhsh]

在 shell 3 或客户端 2 中,我有:

client_1@jahanbakhsh: "Test message\n"
>>>

【讨论】:

  • 感谢您的回复。我确实设法最终对其进行了排序,这似乎是您和 Pascals 答案的混合。 ;)
猜你喜欢
  • 2018-04-18
  • 1970-01-01
  • 2013-06-01
  • 2012-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多