如何让Erlang客户端/服务器与config中的参数/节点连接?

时间:2017-04-18 08:37:32

标签: erlang client-server nodes distributed

我在Erlang中编写客户端/服务器系统并且无法连接它们。他们应该使用的节点存储在配置文件中,配置文件在启动时加载。他们还使用几种分布式数据结构。问题是,我首先启动数据结构,然后是服务器(工作正常),但是当我启动客户端时,它不会连接到任何东西并抛出异常。

服务器:

-module(server).

-export([startServer/0,loopServer/7,node/0,log/0,name/0]).
-compile({no_auto_import,[node/0]}).
-import(werkzeug, [get_config_value/2,lengthSL/1,logging/2,reset_timer/3,get_config_value/2]).
-import(erlang, [append/2]).

log() ->
    erlang:list_to_atom(lists:concat(["Server@", node(),".log"])).

node() ->
    {ok,Config} = file:consult("configs/server.cfg"), 
    {ok, Node} = werkzeug:get_config_value(node,Config),
    Node.

name() ->
    {ok,Config} = file:consult("configs/server.cfg"), 
    {ok, Name} = werkzeug:get_config_value(servername,Config),
    Name.


%%Startet den Server und die darin enthaltene Schleife
startServer() -> 
    {ok,Config} = file:consult("configs/server.cfg"), 
    {ok, Name} = get_config_value(servername,Config),

    %%CMEM initialisieren
    {ok, RemTime} = get_config_value(cmemtime,Config),
    CMEM = cmem:initCMEM(RemTime, log()),

    %%HBQ-Prozess erzeugen
    {ok,HBQName} = get_config_value(hbqname,Config),
    {ok,HBQNode} = get_config_value(node,Config),
    HBQ = {HBQName,HBQNode},

    {ok,Serverzeit} = get_config_value(serverzeit,Config),
    %%Zeitpunkt des Timer übergeben
    {ok, Timer} = timer:send_after(round(RemTime * 1000),Name,delServer),

    %%Prozess registrieren, Serverschleife mit allen Infos starten, plus NNr 1
    ServerPid = spawn(?MODULE, loopServer, [Name,CMEM,HBQ,Timer,Serverzeit,Config,1]),                                                          
    register(Name,ServerPid),

    %%HBQ initialisieren
    HBQ ! {ServerPid, {request,initHBQ}},

    {Config,CMEM,HBQ,ServerPid}.


loopServer(Name,CMEM,HBQ,Timer,Serverzeit,Config,NNr) ->
    receive
        %%Client fragt neue Nachrichten ab, dazu wird aus CMEM die aktuelle NNr für 
        %%den Client angefordert und mit der ClientPID an die HBQ weitergegeben
        {ClientPID,getmessages} ->
            NewTimer = reset_timer(Timer,Serverzeit,delServer),
            ClientNNr = cmem:getClientNNr(CMEM, ClientPID),
            HBQ ! {self(), {request, deliverMSG, ClientNNr, ClientPID}},
            logging(log(), lists:concat(["Server: Nachricht ", NNr, " wurde zugestellt.\n"])),

            loopServer(Name,CMEM,HBQ,NewTimer,Serverzeit,Config,NNr);

        %%Nachricht soll in HBQ verschoben werden
        {dropmessage,[INNr,Msg,TSclientout]} ->
            NewTimer = reset_timer(Timer,Serverzeit,delServer),
            HBQ ! {self(), {request,pushHBQ,[INNr,Msg,TSclientout]}},
            receive
                {reply,ok} ->
                logging(log(), lists:concat(["Server: Nachricht ", INNr, " wurde in HBQ eingefuegt.\n"]))
            end,
            loopServer(Name,CMEM,HBQ,NewTimer,Serverzeit,Config,NNr);

        %%Client fragt naechste NNr ab, diese wird dem Zustand des Server entnommen
        {ClientPID,getmsgid} ->
          NewTimer = reset_timer(Timer,Serverzeit,delServer),
          ClientPID ! {nid, NNr},
          NewNNr = NNr + 1,
          logging(log(), lists:concat(["Server: Nachrichtennumer ", NNr, " an ", erlang:pid_to_list(ClientPID), "gesendet.\n"])),
          loopServer(Name,CMEM,HBQ,NewTimer,Serverzeit,Config,NewNNr);

        %%Server beendet sich selbst und zugleich die HBQ
        delServer ->
            HBQ ! {self(),{request,delHBQ}},
            receive
                {reply,ok} ->
                logging(log(), lists:concat([lists:concat(["Server: Downtime ", werkzeug:timeMilliSecond(), " von ", name() ,"\n"])])),
                ok
            end
    end.

客户端:

-module(client).

-export([startClients/0,loopClient/4,spawnC/1,forLoop/3,mitServerVerbinden/6,configLaden/0]).

-import(werkzeug, [get_config_value/2]).
-import(timer, [apply_after/4]).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%   Client  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%initClient
startClients() ->
  Config = configLaden(),
  {ok, ClientAnzahl} = werkzeug:get_config_value(clientanzahl, Config),
  {ok, ServerName} = werkzeug:get_config_value(servername, Config),
  {ok, ServerNode} = werkzeug:get_config_value(servernode, Config),
  ServerPid = {ServerName,ServerNode},
forLoop(ClientAnzahl, fun client:spawnC/1, ServerPid).


%%Hilfsfunktion fuer for-Schleife: Zaehlt runter,
%%ruft Funktion auf und gibt Ergebnisse als Liste zurueck
forLoop(Clients, Spawn, SPid) -> forLoop(Clients, Spawn, SPid, []).
forLoop(0, _Spawn, _SPid, ClientListe) -> ClientListe;
forLoop(Clients, Spawn, SPid, ClientListe) ->
  ClientListeNew = ClientListe ++ [Spawn(SPid)],
  ClientsNew = Clients - 1,
forLoop(ClientsNew, Spawn, SPid, ClientListeNew).

%%Neuen ClientProzess erzeugen
spawnC(ServerPid) ->
  Config = configLaden(),
  {ok, Lebenszeit} = werkzeug:get_config_value(lebenszeit, Config),
  {ok, Cookie} = werkzeug:get_config_value(cookie, Config),
  {ok, ServerNode} = werkzeug:get_config_value(servernode, Config),
  {ok, Wartezeit} = werkzeug:get_config_value(wartezeit, Config),
  ClientPid = erlang:spawn(?MODULE, mitServerVerbinden, [ServerPid, [], [], Wartezeit, ServerNode, Cookie]),
  timer:kill_after(Lebenszeit, ClientPid),
ClientPid.

%%mit Server Verbinden
mitServerVerbinden(ServerPid,Datei,NNummern,Wartezeit,ServerNode,Cookie) ->
  erlang:set_cookie(ServerNode,Cookie),
  pong = net_adm:ping(ServerNode),
loopClient(ServerPid,NNummern,Wartezeit,Datei).



%%loopClient
loopClient(ServerPid,NNummern,Wartezeit,Datei) ->

  %%Client wird zum Redakteur
  {NNummernNew, WartezeitNew, DateiNew} = nachrichtenSenden(5,ServerPid,NNummern,Wartezeit,Datei),

  %%Client wird zum Leser
  nachrichtenLesen(false, NNummernNew, ServerPid,DateiNew),

  %%Methode ruft sich selbst wieder auf
  loopClient(ServerPid, NNummernNew, WartezeitNew,DateiNew).


configLaden() ->
  {ok, Config} = file:consult("configs/client.cfg"),
  Config. 




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Redakteur %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%Nachricht soll vergessen werden
nachrichtenSenden(0,ServerPid,NNummern,Wartezeit,Datei) ->

  %%Naechste NNr beim Server anfragen
  ServerPid ! {self(),getmsgid},
  receive 

    %%Server sendet NNr
    {nid,NNr} ->

      %%Logeintrag
  werkzeug:logging(Datei,lists:concat([NNr, "te Nachricht um ", werkzeug:timeMilliSecond(), " vergessen zu senden. ******\n"]))
    end,
  WartezeitNew = wartezeitBerechnen(Wartezeit),

  %%Rückgabewerte: Liste mit Nachrichtennummern fuer leser, neue Wartezeit, Logfile
  {NNummern,WartezeitNew,Datei};




%%Nachrichtennummer anfragen und erhalten, Nachricht schreiben
nachrichtenSenden(NachrichtenVorVergessen,ServerPid,NNummern,Wartezeit,Datei) ->
  Config = configLaden(),
  {ok, ServerNode} = werkzeug:get_config_value(servernode, Config),

  %%Naechste NNr beim Server anfragen
  ServerPid ! {self(),getmsgid},
  receive

    %%Server sendet NNr
    {nid,NNr} ->

     %%Nachricht schreiben
     Nachricht = nachrichtSchreiben(NNr),

      %%NNr zur Liste hinzufuegen fuer Leser
      NNummernNew = NNummern ++[NNr],
      timer:sleep(Wartezeit),

      %%Nachricht an Server senden
      ServerPid ! {dropmessage,[NNr,Nachricht,erlang:now()]},

      %%Logeintrag schreiben
      werkzeug:logging(Datei,lists:concat([Nachricht, " gesendet"])),

    %%Neue Wartezeit berechnen  
    WartezeitNew = wartezeitBerechnen(Wartezeit),

    %%Zaehler dekrementieren  
    NachrichtenVorVergessenNew = NachrichtenVorVergessen -1,

  %%Methode neu aufrufen
  nachrichtenSenden(ServerPid,NNummernNew,WartezeitNew,NachrichtenVorVergessenNew,Datei)
  end.



%%nachrichtSchreiben
nachrichtSchreiben(NNr) ->
  Config = configLaden(),
  {ok, Rechner} = werkzeug:get_config_value(rechner, Config),
  {ok, Praktikumsgruppe} = werkzeug:get_config_value(praktikumsgruppe, Config),
  {ok, Teamnummer} = werkzeug:get_config_value(teamnummer, Config),
lists:concat(["client@",Rechner, "_", Praktikumsgruppe, "_", Teamnummer, ": ", integer_to_list(NNr), "_te Nachricht. Sendezeit: ", werkzeug:timeMilliSecond()]).


%%Hilfsmethode: Intervall darf nicht kleiner als zwei Sekunden werden
minimumTime() -> 2000.

%%Berechnet das neue Zeitintervall, um die Haelfte groesser oder
%%kleiner als die alte Zeit, solange sie groesser gleich 2 Sekunden ist
wartezeitBerechnen(Wartezeit) -> 
    GroesserKleiner = werkzeug:bool_rand(),
  HaelfteZeit = trunc(max(Wartezeit * 0.5, minimumTime())),
  if
    GroesserKleiner ->
      Wartezeit + HaelfteZeit;
    true ->
      max(Wartezeit - HaelfteZeit, minimumTime())
end.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    Leser   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


nachrichtenLesen(true,NNummern,ServerPid,Datei) -> ok;

nachrichtenLesen(false,NNummern,ServerPid,Datei) ->
  ServerPid ! {self(),getmessages},
  receive 
    {reply,Message,Terminated} ->
    nachrichtInLogSchreiben(Message,NNummern,Datei),
    nachrichtenLesen(Terminated,NNummern,ServerPid,Datei)
  end.

nachrichtInLogSchreiben([NNr,Msg,TSclientout,TShbqin,TSdlqin,TSdlqout],NNummern,Datei) ->
  Now = erlang:timestamp(),
  DLQInTrue = werkzeug:validTS(TSdlqin),
  DLQOutTrue = werkzeug:validTS(TSdlqout),
  DLQInZukunft = werkzeug:lessTS(Now, TSdlqin),
  DLQOutZukunft = werkzeug:lessTS(Now, TSdlqout),
  MsgVonGleichemClient = msgVonGleichemClient(NNr, Msg, NNummern),
  if
      DLQInTrue and DLQInZukunft ->
      Zeitunterschied = werkzeug:now2stringD(werkzeug:diffTS(TSdlqin, Now)),
      MsgNew = MsgVonGleichemClient ++ ", Zeitunterschied: " ++ Zeitunterschied,
      werkzeug:logging(Datei, MsgNew ++ "\n");
    DLQOutTrue and DLQOutZukunft ->
      Zeitunterschied = werkzeug:now2stringD(werkzeug:diffTS(TSdlqout, Now)),
      MsgNew = MsgVonGleichemClient ++ ", Zeitunterschied: " ++ Zeitunterschied,
      werkzeug:logging(Datei, MsgNew ++ "\n");
    true ->
      werkzeug:logging(Datei, MsgVonGleichemClient ++ "\n")
  end.


msgVonGleichemClient(NNr,Msg,NNummern) ->
    MsgVonGleichemClient = lists:member(NNr, NNummern),
  if
    MsgVonGleichemClient -> Msg ++ "*******";
    true -> Msg
end.

服务器的配置文件:

{sizedlq,400}.
{servername,'serverpa'}.
{cmemtime,2000}.
{hbqname,'hbqpa'}.
{node,'hbqnode'}.
{serverzeit,50}.

客户端的配置文件:

{wartezeit,20}.
{lebenszeit,240}.
{pratikumsgruppe,'2'}.
{teamnummer,'02'}.
{servername,'serverpa'}.
{clientanzahl,5}.
{servernode,'servernode'}.
{cookie,pa}.
{rechner,'rechner'}.

还有分布式数据结构,它们本质上是队列,似乎工作正常:

HBQ:

-module(hbq).

-export([startHBQ/0, checkTransfer/6,loophbq/4]).

%%      HBQ !{self(), {request,pushHBQ,[INNr,Msg,TSclientout]}}

startHBQ() ->
  startHBQ("./configs/server.cfg").

%% Used for starting the HBQ with a custom config file


startHBQ(Configfile) ->
        %%Config und Namen auslesen
        Config = loadConfig(Configfile),
    Config = loadConfig(Configfile),
        %%{ok,Config} = file:consult("./config/server.cfg"),
        {ok,HBQName} = werkzeug:get_config_value(hbqname,Config),

        %%Prozess der HBQ starten
        HBQPid = spawn(?MODULE,loophbq,[[],[],Config, 1]),

        %%Prozess registrieren
        register(HBQName,HBQPid),
        HBQPid.



loophbq(HBQ,DLQ,Config,CurrNumber) ->
    receive 
        %%initialisere HBQ und DLQ, sendet ok an Server
        {ServerPid,{request,initHBQ}} ->
            HBQList = [],
            Log = log(Config,["HBQ>>> initialisiert worden von ", ServerPid, ".\n"]),
            {ok,DLQSize} = werkzeug:get_config_file(sizedlq,Config),
            DLQ = dlq:initDLQ(DLQSize,Log),
            ServerPid ! {reply,ok},
            loophbq(HBQList, DLQ ,Config, CurrNumber);      

        %%fuegt der Msg einen Zeitstempel hinzu, fuegt sie in HBQ ein, sendet ok
        {ServerPid,{request,pushHBQ,[NNr,Msg,TSclientout]}} ->  
            TShbqin = werkzeug:timeMillliSecond(),
            NewMessage = {NNr,lists:concat(Msg,["HBQ in: ",TShbqin])},
            Log = log(Config,["HBQ>>> Nachricht ",NNr, "in HBQ eingefügt.\n"]),
            NewHBQ = [HBQ|NewMessage],
            lists:sort(fun({A,_},{B,_}) -> A=<B end),       
            checkTransfer(NewHBQ, CurrNumber, Config, DLQ,TSclientout,TShbqin),
            ServerPid ! {reply,ok}, 
            loophbq(NewHBQ, DLQ ,Config, CurrNumber);

        %%DLQ soll über HBQ Nachricht an Client senden
        {ServerPid,{request,deliverMSG,NNr,ToClient}} ->
            {ok, HBQName} = werkzeug:get_config_value(hbqname, Config),
            Log = lists:concat(["HB-DLQ@", HBQName, ".log"]),
            Datei = erlang:list_to_atom(Log),
            log(Config, ["HBQ>>> dlq:delivermsg", NNr, pid_to_list(ToClient), "\n"]),
            NNrDLQ = dlq:deliverMSG(NNr, ToClient, DLQ, Datei),
            ServerPid ! {reply, NNrDLQ},
            loophbq(HBQ, DLQ ,Config, CurrNumber);

        %%Terminiert Prozess der DLQ
        {ServerPid,{request,delHBQ}} ->
            ServerPid ! {reply,ok},
            ok
      end.


%%CheckTransfer
checkTransfer(HBQ, Number, Config, [DLQ,Size],TSclientout,TShbqin) -> 
    Datei = log(Config, ["HBQ>>> Nachricht Nr ", Number, " wird in DLQ uebertragen\n"]),
    FoundMatch = lists:keyfind(Number, 1, HBQ),
    if  FoundMatch =:= false ->
        if(length(HBQ)>Size*0.667) -> 
        [{MinNNr,_}|_] = HBQ,
        %wegen sort ist immer die kleinste NNr vorne in der Liste 
        NewMessage = {MinNNr-1,lists:concat(["Weiß noch nicht was hier reinsoll: ",werkzeug:timeMilliSecond()])},
        NewHBQ = lists:append([{MinNNr-1,NewMessage}], HBQ),
        log(Config,["HBQ>>> Fehlernachricht fuer Nachrichten ",Number," bis",MinNNr-1, " generiert.\n"]),
        NewNumber = MinNNr-1,
        checkTransfer(NewHBQ, NewNumber, Config,[DLQ,Size],TSclientout,TShbqin);
        true -> ok
        end;
    true ->
        {MatchNr,Msg} = FoundMatch,
        dlq:push2DLQ([MatchNr, Msg, TSclientout, TShbqin], DLQ, Datei),
        lists:delete(FoundMatch, HBQ),
        checkTransfer(HBQ, Number+1, Config,[DLQ,Size],TSclientout,TShbqin)
end.



log(Config,Message) -> 
    {ok,HBQNode} = werkzeug:get_config_value(node,Config),
    DateiName = lists:concat(["HB-DLQ@", HBQNode,".log"]),
    Datei = erlang:list_to_atom(DateiName),
    werkzeug:logging(Datei, lists:concat(Message)),
    Datei.

%%Dummy-Nachrichten schreiben um Lücken in der HBQ zu füllen wenn sie kritische Größe erreicht

%%Methode um zu prüfen, ob Nachrichten in DLQ geschoben werden können, das dann auch machen
loadConfig(Configfile) ->
  {ok, Config} = file:consult(Configfile),
Config.

DLQ:

-module(dlq).

-export([initDLQ/2, delDLQ/1, expectedNr/1, push2DLQ/3, deliverMSG/4]).

%%Initialisiert DLQ mit Kapazitaet Size, Log in Datei
initDLQ(Size, Datei) -> 
werkzeug:logging(Datei,lists:concat(["DLQ>>> intitialisiert worden mit Groesse ",Size,".\n"])),
[[],Size].

%%Loescht DLQ
delDLQ(_Queue) -> ok.

%%Liefert NNr die als naechstes in DLQ gespeichert werden kann
%%expectedNr(Queue)
expectedNr([[], _Size]) -> 1;
expectedNr([[[NNr, _Msg, _TSclientout, _TShbqin, _TSdlqin] | _Rest], _Size]) -> NNr + 1.

%%Speichert Nachricht in DLQ, fuegt Zeitstempel hinzu, Rueckgabe: Modifizierte DLQ
%%push2DLQ([NNr, Msg, TSclientout, TShbqin], Queue, Datei)
%%Fehlt noch: Abfrage, ob das die passende Nummer ist!

push2DLQ([NNr, Msg, TSclientout, TShbqin], [DLQ,Size], Datei) ->
  if
    length(DLQ) < Size ->
      werkzeug:logging(Datei, lists:concat(["DLQ>>> Nachricht ", NNr, " in DLQ eingefügt.\n"])),
      [[[NNr, Msg, TSclientout, TShbqin, erlang:now()] | DLQ], Size];
    length(DLQ) =:= Size ->
      [LastNNr, _Msg, _TSclientout, _TShbqin, _TSdlqin] = lists:last(DLQ),
      werkzeug:logging(Datei, lists:concat(["DLQ>>> Nachricht ", LastNNr, " aus DLQ entfernt.\n"])),
      werkzeug:logging(Datei, lists:concat(["DLQ>>> Nachricht ", NNr, " in DLQ eingefügt.\n"])),
      [[[NNr, Msg, TSclientout, TShbqin, erlang:now()] | lists:droplast(DLQ)], Size]
end.

%%Sendet Nachricht an Leser-Client
deliverMSG(MSGNr, ClientPID, Queue, Datei) ->

  %%Aendern: MSGNer = -1, flag am Ende der Reply (siehe zeile 42)
    [{NewestNr,Msg}|Rest] = Queue,
    if MSGNr > NewestNr ->
           DummyMessage = {-1,lists:concat(["DLQ in: ",werkzeug:timeMilliSecond()])}, %% -1 Flag
            werkzeug:logging(Datei, lists:concat(["DLQ>>> DummyNachricht fuer ",MSGNr," an Client ",ClientPID, " ausgeliefert.\n"])),
            ClientPID ! {reply,Msg,true}
    end,    
%%%%%%Ab hier noch aendern bzgl Flag
        FoundMatch = lists:keyfind(MSGNr, 1, Queue),
        if
          FoundMatch =:= false -> 
            deliverMSG(MSGNr+1, ClientPID, Queue, Datei),
         if 
       MSGNr =:= NewestNr ->
            {Number,Msg} = FoundMatch,
            NewMessage = {Number,lists:concat(Msg,["DLQ in: ",werkzeug:timeMilliSecond()],-1)},
            werkzeug:logging(Datei, lists:concat(["DLQ>>> Nachricht ", Number, " an Client ",ClientPID, " ausgeliefert.\n"])),
            ClientPID ! {reply,Msg,false};
        true ->
        {Number,Msg} = FoundMatch,
            NewMessage = {Number,lists:concat(Msg,["DLQ in: ",werkzeug:timeMilliSecond()],0)},
            werkzeug:logging(Datei, lists:concat(["DLQ>>> Nachricht ", Number, " an Client ",ClientPID, " ausgeliefert.\n"])),
            ClientPID ! {reply,Msg,false}
         end;
     true ->
        ok
        end.

CMEM:

-module(cmem).

-export([initCMEM/2, delCMEM/1, updateClient/4, getClientNNr/2]).

-import(werkzeug, [get_config_value/2,lengthSL/1,logging/2,reset_timer/3,get_config_value/2,getUTC/0]).

%%Initialisiert CMEM
initCMEM(RemTime, Datei) -> werkzeug:logging(Datei, lists:concat(["CMEM>>> initialisiert mit  ", RemTime, " Sekunden\n"])),
  [[], RemTime].

%%Loescht CMEM
delCMEM(_CMEM) -> ok.

%%Speichert/aktualisiert Client und NNr im CMEM, 
updateClient([CMEM, RemTime], ClientID, NNr, Datei) -> 
  ClientTS = getUTC(),
  logging(Datei, lists:concat(["CMEM>>> Client ", ClientID, " wird aktualisiert.\n"])),
  [lists:keystore(ClientID, 1, CMEM, {ClientID, NNr, ClientTS}), RemTime].

%%Gibt naechste vom Client erwartete NNr zurueck
%%Es wird geprueft ob Client in der Liste steht und dann
%%mit diesem Wissen eine Hilfsfunktion aufgerufen
getClientNNr([CMEM, RemTime], ClientID) ->
  ClientBekannt = lists:keymember(ClientID, 1, CMEM),
  isClientKnown([CMEM, RemTime], ClientID, ClientBekannt).

%%Client ist nicht bekannt: Naechste NNr = 1
isClientKnown(_CMEM, _ClientID, false) -> 1;

%% Der Client ist bekannt.
%%Zeit noch nicht abgelaufen: Gibt naechste Nummer aus
%%Zeit abgelaufen: Naechste NNr = 1
isClientKnown([CMEM, RemTime], ClientID, true) ->
  {ClientID, NNr, ClientTS} = lists:keyfind(ClientID, 1, CMEM),
  RemainingTime = ClientTS + RemTime,
  Now = getUTC(),
  if
    RemainingTime >= Now -> NNr + 1;
    true -> 1
end.

客户端应该联系服务器向其发送消息,服务器将其放入数据结构中,并在适当的情况下将其发送回客户端。 问题是,当我编译它们时,启动HBQ,然后启动服务器,然后启动客户端,我得到

=ERROR REPORT==== 18-Apr-2017::10:25:46 ===
Error in process <0.104.0> with exit value: {distribution_not_started,[{auth,set_cookie,2,[{file,"auth.erl"},{line,119}]},{client,mitServerVerbinden,6,[{file,"client.erl"},{line,42}]}]}

显然,客户端没有连接到服务器存在问题。这是我第一次使用Erlang和分布式系统,所以我不知道发生了什么。

将节点和cookie放入配置并告诉系统组件在那里看是不够的?

1 个答案:

答案 0 :(得分:0)

当调用它的erlang VM没有名称时,auth模块会返回错误distribution_not_started。确保在启动erlang时传递-sname-name标志,例如:

erl -sname test