خطأ استثناء: وظيفة غير محددة في mochiweb / erlang

StackOverflow https://stackoverflow.com/questions/982309

  •  13-09-2019
  •  | 
  •  

سؤال

بعد رؤية هذه المقالة, ، لقد كنت العبث مع mochiweb. أثناء محاولة نسخ تكرار ما تم القيام به في المقالة - إعداد خادم MochiWeb بشكل أساسي، وجود عقدتين Erlang، ثم استدعاء وظيفة محددة في عقدة واحدة في أخرى (بعد الإعداد NET_ADM: Ping () بين العقدتين حتى يعرفون كل منها آخر).

كنت قادرا على اتباع كل شيء حتى جزء استدعاء الوظيفة. في N1 @ LocalHost، وهو خادم MochiWeb، أسمي (تماما كما فعلت في المقالة):

router:login(IdInt, self()).

ثم، في N2 @ LocalHost، وهو البرنامج النصي Router.erl، لقد حددت وظيفة تسجيل الدخول:

login(Id, Pid) when is_pid(Pid) ->
    gen_server:call(?SERVER, {login, Id, Pid}).

handle_call({login, Id, Pid}, _From, State) when is_pid(Pid) ->
          ets:insert(State#state.pid2id, {Pid, Id}),
          ets:insert(State#state.id2pid, {Id, Pid}),
          link(Pid), % tell us if they exit, so we can log them out
          io:format("~w logged in as ~w\n",[Pid, Id]),
          {reply, ok, State};

لقد قمت بلصق الأجزاء ذات الصلة فقط من التعليمات البرمجية. ومع ذلك، عندما أصل إلى WebServer الآن على المستعرض - أحصل على تقرير الخطأ هذا على N1 @ LocalHost:

=CRASH REPORT==== 11-Jun-2009::12:39:49 ===
  crasher:
    initial call: mochiweb_socket_server:acceptor_loop/1
    pid: <0.62.0>
    registered_name: []
    exception error: undefined function router:login/2
      in function  mochiconntest_web:loop/2
      in call from mochiweb_http:headers/5
    ancestors: [mochiconntest_web,mochiconntest_sup,<0.59.0>]
    messages: []
    links: [<0.61.0>,#Port<0.897>]
    dictionary: [{mochiweb_request_path,"/test/123"}]
    trap_exit: false
    status: running
    heap_size: 1597
    stack_size: 24
    reductions: 1551
  neighbours:

=ERROR REPORT==== 11-Jun-2009::12:39:49 ===
{mochiweb_socket_server,235,{child_error,undef}}

بعد Googling حولها، حصلت على Googlegling حول الخطأ الذي يحاول الخطأ القول - وهو أساسا يقول أن وظيفة تسجيل الدخول التي يتم استدعاؤها في N1 @ LocalHost غير محددة - ولكن يتم تعريفها في N2 @ LocalHost (وكلا العقدتين تعرف كل منهما أخرى - فعلت nodes(). للتأكد) !! من فضلك قل لي أين أنا مخطئ!

هل كانت مفيدة؟

المحلول

أنت على حق - رمز جهاز التوجيه: تسجيل الدخول غير متوفر بالفعل على المضيف الخاص بك N1 @ LocalHost - إنه الرمز داخل هذه الوظيفة (Gen_Server: وظيفة الاتصال) التي تسجل المكالمة إلى N2 @ LocalHost (عبر ذلك؟ ماكرو الخادم) وهذا هو المكان الذي هو التنفيذ الحقيقي هو. وظيفة المستوى الأعلى هي ببساطة وسيلة لفصل تلك الاتصال بالعقدة المناسبة.

لكنك بحاجة إلى تنفيذ تسجيل الدخول على الأقل

login(Id, Pid) when is_pid(Pid) ->
    gen_server:call(?SERVER, {login, Id, Pid}).

متوفر على N1 @ localhost.

(محدث)

كنت بحاجة إلى تحديد ماكرو خادم أو استبداله أو لنا كذلك. في نموذج التعليمات البرمجية في المقالة هذا هو

-define(SERVER, global:whereis_name(?MODULE)).

ولكن هذا يستخدم ماكرو الوحدة النمطية التي ستكون خاطئة في قضيتك. في الأساس عند بدء تشغيل عملية Gen_Server (جهاز التوجيه)، يسجل نفسها على النحو الأول؟ لذلك يجب أن تكون قادرا على كتابة:

login(Id, Pid) when is_pid(Pid) ->
    gen_server:call(global:whereis_name(router), {login, Id, Pid}).

لذلك فإن تأثير الدعوة في تسجيل الدخول على N1 @ LocalHost سيجعل مكالمة Gen_Server إلى جهاز التوجيه: Witle_Call الطريقة على n2 @ localhost، على افتراض أن عملية التوجيه gen_server قيد التشغيل وتسجل نفسها. تعود قيمة الإرجاع هذه المكالمة إلى العملية الخاصة بك على N1 @ LocalHost.

نصائح أخرى

في الأمثلة في سؤالك يبدو أنك تحميل فقط router وحدة على عقدة واحدة. العقد لا تفترض تلقائيا تحميل التعليمات البرمجية تلقائيا من بعضنا البعض، لذلك لمجرد تعريف الوظيفة على N2، لا يعني أنه يمكنك الاتصال به محليا في N1 (N1) يجب أن تكون قادرا على تحميلها بالطريقة العادية).

يبدو الكود الذي ينظر إليه وكأنه يتلاءم بشكل صحيح مع التشغيل في نظام موزز (يمكنك بدء تشغيل خادم التوجيه على عقدة واحدة واستدعاء وظائف API على العقد الأخرى سوف يرسل طلبات التوجيه إلى المكان الصحيح). لذلك تحتاج فقط إلى وضع نسخة من router الوحدة النمطية على N1 وينبغي أن تعمل فقط. من الممكن تحميل N1 router الوحدة النمطية من N2، ولكنها قليلة من المتاعب مقارنة مع مجرد إعطاء N1 نسخة من الوحدة النمطية في مسار التعليمات البرمجية.

ومن المثير للاهتمام، في رمز التوجيه لا لزوم لها gen_server:call(global:whereis_name(?MODULE, Message)). كما gen_server:call/2 تعرف الوظيفة كيفية البحث في التسجيلات العالمية نفسها. -define(SERVER, {global, ?MODULE}). سوف تعمل بشكل جيد إذا قمت بتغيير وظيفة start_link إلى start_link() -> gen_server:start_link(?SERVER, ?MODULE, [], []).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top