[erlang-questions] Comunication between 2 gen_server's
Ladislav Lenart
lenartlad@REDACTED
Fri Apr 13 10:09:05 CEST 2012
Hello.
I don't understand the following:
You can't register the client because this would be generic.
You implement chat_server and chat_client as gen_server modules.
Something like the following (WARNING: The code is incomplete and
untested!)...
%%%%%%%%%%%%%%
%%% SERVER %%%
%%%%%%%%%%%%%%
-module(chat_server).
-export(...).
%%% API
start(SrvName) ->
gen_server:start({local, SrvName}, ?MODULE, [], []).
start_link(SrvName) ->
gen_server:start_link({local, SrvName}, ?MODULE, [], []).
stop(Srv) ->
gen_server:cast(Srv, stop).
%% Connect a chat client process to a chat server.
connect_client(Srv, Client) ->
gen_server:call(Srv, {connect_client, Client}).
%% Send Msg (a string) from a Nick to all currently connected clients.
broadcast_message(Srv, Nick, Msg) ->
gen_server:cast(Srv, {broadcast_message, Nick, Msg}).
%%% Callbacks
init([]) ->
%% This way the server will be informed about termination
%% of its clients (see handle_info/2 below).
erlang:process_flag(trap_exit, true),
{ok, []}.
handle_call({connect_client, Client}, Clients) ->
%% Establish a two-way relationship between the server and Client.
%% Because of process_flag/2 above, the server will be notified if
%% Client terminates for whatever reason.
erlang:link(Client),
{reply, ok, [Client | Clients]}.
handle_cast({broadcast_message, SenderNick, Msg}, Clients) ->
lists:foreach(fun (Client) ->
chat_client:receive_message(Client, SenderNick, Msg)
end,
Clients),
{noreply, Clients};
handle_cast(stop, Clients) ->
%% This will automatically terminate all connected clients.
{stop, shutdown, Clients}.
handle_info({'EXIT', Client, _Reason}, Clients) ->
{noreply, lists:delete(Client, Clients)}.
%%%%%%%%%%%%%%
%%% CLIENT %%%
%%%%%%%%%%%%%%
-module(chat_client).
-export(...).
-record(state, {nick, server}).
%%% API
start(Nick, Srv) ->
gen_server:start(?MODULE, [Nick, Srv], []).
start_link(Nick, Srv) ->
gen_server:start_link(?MODULE, [Nick, Srv], []).
stop(Client) ->
%% This will inform the server about the end of my life.
exit(Client, shutdown).
say(Client, Msg) ->
gen_server:cast(Client, {say, Msg}).
%% Called by the chat_srv during its broadcast_message/2 to
%% deliver Msg to each connected client.
receive_message(Client, SenderNick, Msg) ->
gen_server:cast(Client, {receive_message, SenderNick, Msg}).
%%% Callbacks
init([Nick, Srv]) ->
self() ! connect,
{ok, #state{nick=Nick, server=Srv}}.
handle_cast({say, Msg}, #state{server=Srv, nick=Nick} = State) ->
chat_server:broadcast_message(Srv, Nick, Msg),
{noreply, State};
handle_cast({receive_message, SenderNick, Msg}, State) ->
io:format("~p: ~p~n", [SenderNick, Msg]),
{noreply, State};
handle_info(connect, State) ->
ok = chat_server:connect_client(State#state.server, self()),
{noreply, State}.
%%%%%%%%%%%%%
%%% USAGE %%%
%%%%%%%%%%%%%
srv_node> chat_srv:start(chat).
{ok, ...}
client_1> {ok, AdamPid} = chat_client:start("Adam", {chat, srv_node}).
{ok, AdamPid}
client_2> {ok, EvePid} = chat_client:start("Eve", {chat, srv_node}).
{ok, EvePid}
client_1> chat_client:say(AdamPid, "Hello!").
ok
Adam: Hello!
client_2>
Adam: Hello!
client_2> chat_client:say(EvePid, "Oh, hi handsome!").
ok
Eve: Oh, hi handsome!
client_1>
Eve: Oh, hi handsome!
Call chain to start new client (server must be already running):
1. [Client shell] chat_client:start(Nick, Srv).
2. [Chat client] chat_client:init([Nick, Srv]).
3. [Chat client] chat_client:handle_info(connect,...).
4. [Chat client] chat_server:connect_client(Srv, self()).
5. [Chat server] chat_server:handle_call({connect_client, Client},...).
Call chain to send a message (server and client are running):
1. [Client shell] chat_client:say(Client, Msg).
2. [Chat client] chat_client:handle_cast({say, Msg},...).
3. [Chat client] chat_server:broadcast_message(Srv, SenderNick, Msg).
4. [Chat server] chat_server:handle_cast({broadcast_message, SenderNick, Msg),...).
5. [Chat server] For each connected client:
5.1 [Chat server] chat_client:receive_message(EachClient, SenderNick, Msg).
5.2 [Chat client] chat_client:handle_cast({receive_message, SenderNick, Msg},...).
What's missing:
* Some of the server internals.
* Some of the client internals.
* Tests.
* Store messages on clients for further processing instead of just
printing them.
* You can generate and broadcast automatic connect / disconnect
messages.
Hope this helps,
Ladislav Lenart
On 12.4.2012 23:39, megalomania wrote:
> up!
> Well im trying make a gen_server for a client, but i dont now how get the
> messages that server sends, i cant register the client cuz this would be
> generic, any idea?
>
> --
> View this message in context: http://erlang.2086793.n4.nabble.com/Comunication-between-2-gen-server-s-tp4551836p4553168.html
> Sent from the Erlang Questions mailing list archive at Nabble.com.
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions
>
More information about the erlang-questions
mailing list