[erlang-questions] Help! with gen_server and a chat_server

Mike Oxford <>
Thu Apr 12 07:40:42 CEST 2012


Unfortunately there are quite a number of things wrong. =(

You should read this:
http://www.erlang.org/doc/getting_started/conc_prog.html
I would suggest going through the tutorial on  http://learnyousomeerlang.com .
 It's quite good.

Here's why your code crashed...

*()27> {} !*
*servidor:call(login,irene,6666).
** exception error: undefined function servidor:call/3
*
You told it to call servidor:call/3, but that does not exist.  You should
be using gen_server:call/2 (see below). If it did, it would make the call
and try to send the return code to  *{}* *.*
*
*
*()28> {} ! servidor:login(irene,6666).
** exception exit: {noproc,{gen_server,call,[servidor,{login,irene,6666}]}}
    in function  gen_server:call/2
*
You now called servidor:login/2 locally, which worked but tried to
gen_server:call back to itself (via ?MODULE) to do a login.  However,
servidor is not running on  *()* ... it's running on *
{}*

*()29> {} !
process_request(login,{irene,2321}).
** exception error: undefined shell command process_request/2
*
You ran this from the shell and it doesn't know about process_request/2.
 If it did, the return-value from process_request would be shipped to *
 {}*

Don't mix ! and call/cast.    The receive handlers are slightly different
for OTP stuff ({'$gen_cast',Msg,State} and {'$gen_call',From,Msg,State})
which you have to account for.
If you're using OTP, use OTP calls and handlers.  It's cleaner.

Try gen_server:call( {}, {login, irene,777} ).

Make sure server can login from server  ( such as gen_server:call(self(),
{login, irene, 777} ... and then scale out to multiple nodes.)

-mox


On Wed, Apr 11, 2012 at 4:03 PM, megalomania <> wrote:

> *Hi all,
> Im newbie on Erlang and trying lear to use gen_server but i begin to
> understan that maybe im wrong.
>
> Im just trying to making a chat_server with gen_serve, so the idea is a
> client on an another node could try to login in the chat_server who will be
> in another node.
>
> here is my code:
> *
>
> -module(servidor) .
> -behavior(gen_server) .
>
> % API functions
> -export([start_link/0, hi/0, login/2, logout/1, times/2, stop/0]).
>
> % Callback functions
> -export([init/1, handle_call/3, handle_info/2, terminate/2, handle_cast/2,
> code_change/3]).
>
> -define(NAME_SERVER, ?MODULE).
> -define(LOGUEADOS, logeados).
>
>
> start_link() ->
>        gen_server:start_link({local, ?NAME_SERVER}, ?MODULE, [], []).%Se
> registra
> el proceso con el nombre del modulo(servidor)
>
> hi() ->
>        gen_server:cast(?MODULE, hi) .
>
> stop() ->
>        gen_server:cast(?MODULE, stop).
>
> login(Nick,Pid) ->
>        gen_server:call(?MODULE, {login, Nick, Pid}).
>
> logout(Nick) ->
>        gen_server:call(?MODULE, {logout, Nick}).
>
> times(N, M) ->
>        ?MODULE ! {times_request, self(), {N, M}}.
>
>
>
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> %% Callback functions implementation %%
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
>
> init([]) ->
>        {ok, ets:new(?LOGUEADOS, [set])}.
>
> terminate(_Reason, _State) ->
>        {_, Tab} = _State,
>        ets:delete(Tab),
>        ok.
>
>
> handle_call({login, Nick, Pid}, _From, _State) ->
>        %% En el login habra que crear una nodo del que haga el login //
> Para
> probarlo, miro simplemente si existe en la BD.
>        io:format("Loggin.. y state=~w: ~n", [_State]),
>        BOOL = ets:member(_State, Nick),
>        io:format("The user is online? = ~w ~n", [BOOL]),
>        if
>                BOOL == true -> io:format("~w its already login", [Nick]);
>                true -> ets:insert(_State, {Nick,Pid}), io:format("Login
> succesful ~n")
>        end,
>        {reply, {login, Nick}, _State};
>
>
> handle_call({logout, Nick}, _From, _State) ->
>        io:format("Logout...~n", []),
>        ets:delete(_State, Nick).
>
>
> handle_cast(hi, State) ->
>        io:fwrite("\t\tHi!\~n"),
>        {noreply, State} ;
>
> handle_cast(stop, _State) ->
>        io:format("Stopped~n", []),
>        {_, Tab} = _State,
>        ets:delete(Tab),
>        {stop, normal, _State} .
>
>
> handle_info({times_request, Pid, {N, M}}, State) ->
>        io:fwrite("\t~w server handling info, request number ~w~n",
> [?MODULE,
> State]),
>        Pid ! {times_response, N*M},
>        {noreply, State} .
>
> code_change(_OldVsn, _State, _Extra) ->
>        {ok, _State}.
>
>
> *and then i typed this in one console:*
>
> >erl -sname server
> ()1> c(servidor).
> {ok,servidor}
> ()2> servidor:start_link().
> {ok,<0.45.0>}
> ()3>
>
>
> *and then i typed this in another console:*
> )25> {} ! {servidor,login,irene,777}.
> {servidor,login,irene,777}
> ()26> {} !
> {servidor,login,irene,777}.
> {servidor,login,irene,777}
> ()27> {} !
> servidor:call(login,irene,6666).
> ** exception error: undefined function servidor:call/3
> ()28> {} !
> servidor:login(irene,6666).
> ** exception exit: {noproc,{gen_server,call,[servidor,{login,irene,6666}]}}
>     in function  gen_server:call/2
> ()29> {} !
> process_request(login,{irene,2321}).
> ** exception error: undefined shell command process_request/2
> ()30> {} ! {hi}.
> {hi}
> ()31> {} ! {async,hi}.
>
>
> *almost or the most of instructions makes server_node crash :(*
>
> My question is, what im doing wrong? It is the correct way?
>
>
> --
> View this message in context:
> http://erlang.2086793.n4.nabble.com/Help-with-gen-server-and-a-chat-server-tp4550462p4550462.html
> Sent from the Erlang Questions mailing list archive at Nabble.com.
> _______________________________________________
> erlang-questions mailing list
> 
> http://erlang.org/mailman/listinfo/erlang-questions
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20120411/b021f2c9/attachment.html>


More information about the erlang-questions mailing list