Erlang 21 - 7. C Nodes

7 सी नोड्स




erlang

7 सी नोड्स

यह अनुभाग C नोड का उपयोग करके Problem Example में Problem Example समाधान के तरीके का एक उदाहरण बताता है। ध्यान दें कि सी नोड आमतौर पर इस तरह की सरल समस्याओं को हल करने के लिए उपयोग नहीं किया जाता है, एक पोर्ट पर्याप्त है।

7.1 एर्लांग कार्यक्रम

एरलैंग के दृष्टिकोण से, सी नोड को एक सामान्य एरलंग नोड की तरह माना जाता है। इस प्रकार, फ़ंक्शन foo और bar कॉल करने में केवल सी नोड को एक संदेश भेजना शामिल है जो फ़ंक्शन को कॉल करने के लिए कह रहा है, और परिणाम प्राप्त कर रहा है। किसी संदेश को भेजने के लिए एक प्राप्तकर्ता की आवश्यकता होती है, अर्थात, एक ऐसी प्रक्रिया है जिसे एक पंजीकृत नाम और नोड नाम से मिलकर pid या tuple का उपयोग करके परिभाषित किया जा सकता है। इस मामले में, एक टपल एकमात्र विकल्प है क्योंकि कोई पिड ज्ञात नहीं है:

{RegName, Node} ! Msg

नोड नोड का नाम C नोड का नाम है। यदि शॉर्ट नोड नामों का उपयोग किया जाता है, तो नोड का सादा नाम cN , जहां N एक पूर्णांक होता है। यदि लंबे नोड नाम का उपयोग किया जाता है, तो ऐसा कोई प्रतिबंध नहीं है। लघु नोड नामों का उपयोग करके C नोड नाम का एक उदाहरण इस प्रकार है [email protected] , लंबी नोड नामों का उपयोग करने वाला एक उदाहरण [email protected]

पंजीकृत नाम, RegName , कोई भी परमाणु हो सकता है। नाम को C कोड द्वारा अनदेखा किया जा सकता है, या, उदाहरण के लिए, विभिन्न प्रकार के संदेशों के बीच अंतर करने के लिए उपयोग किया जाता है। लघु नोड नामों का उपयोग करके एरलांग कोड का एक उदाहरण इस प्रकार है:

-module(complex3).
-export([foo/1, bar/1]).

foo(X) ->
    call_cnode({foo, X}).
bar(Y) ->
    call_cnode({bar, Y}).

call_cnode(Msg) ->
    {any, [email protected]} ! {call, self(), Msg},
    receive
	{cnode, Result} ->
	    Result
    end.

लंबे नोड नामों का उपयोग करते समय, कोड थोड़ा अलग है जैसा कि निम्नलिखित उदाहरण में दिखाया गया है:

-module(complex4).
-export([foo/1, bar/1]).

foo(X) ->
    call_cnode({foo, X}).
bar(Y) ->
    call_cnode({bar, Y}).

call_cnode(Msg) ->
    {any, '[email protected]'} ! {call, self(), Msg},
    receive
	{cnode, Result} ->
	    Result
    end.

7.2 सी कार्यक्रम

संचार स्थापित करना

Erl_Interface में किसी अन्य फ़ंक्शन को कॉल करने से पहले, स्मृति हैंडलिंग को आरंभ किया जाना चाहिए:

erl_init(NULL, 0);

अब C नोड शुरू किया जा सकता है। यदि छोटे नोड नामों का उपयोग किया जाता है, तो इसे erl_connect_init() कहकर किया जाता है:

erl_connect_init(1, "secretcookie", 0);

यहाँ:

  • पहला तर्क नोड नाम का निर्माण करने के लिए उपयोग किया जाने वाला पूर्णांक है।

    उदाहरण में, सादा नोड नाम c1

  • दूसरा तर्क मैजिक कुकी को परिभाषित करने वाला एक स्ट्रिंग है।
  • तीसरा तर्क एक पूर्णांक है जिसका उपयोग C नोड के किसी विशेष उदाहरण को पहचानने के लिए किया जाता है।

यदि लंबे नोड नोड नामों का उपयोग किया जाता है, तो erl_connect_xinit() कॉल करके दीक्षा दी जाती है:

erl_connect_xinit("idril", "cnode", "[email protected]",
                  &addr, "secretcookie", 0);

यहाँ:

  • पहला तर्क होस्ट नाम है।
  • दूसरा तर्क सादा नोड नाम है।
  • तीसरा तर्क पूर्ण नोड नाम है।
  • चौथा तर्क मेजबान के आईपी पते के साथ in_addr संरचना का एक संकेतक है।
  • पांचवां तर्क है जादू की कुकी।
  • छठा तर्क उदाहरण संख्या है।

Erlang-C संचार सेट करते समय C नोड सर्वर या क्लाइंट के रूप में कार्य कर सकता है। यदि यह एक क्लाइंट के रूप में कार्य करता है, तो यह erl_connect() कॉल करके एक erl_connect() नोड से erl_connect() , जो सफलता पर एक खुला फ़ाइल विवरणक लौटाता है:

fd = erl_connect("[email protected]");

यदि सी नोड एक सर्वर के रूप में कार्य करता है, तो उसे पहले एक निश्चित पोर्ट नंबर port को सुनना एक सॉकेट (कॉल bind() और listen() ) बनाना होगा। इसके बाद इसका नाम और पोर्ट नंबर epmd , Erlang port मैपर डेमन के साथ प्रकाशित होता है। विवरण के लिए, epmd में epmd मैनुअल पेज देखें:

erl_publish(port);

अब C नोड सर्वर Erlang नोड्स से कनेक्शन स्वीकार कर सकता है:

fd = erl_accept(listen, &conn);

erl_accept का दूसरा तर्क एक संरचना है ErlConnect जिसमें उपयोगी जानकारी है जब एक कनेक्शन स्थापित किया गया है, उदाहरण के लिए, ErlConnect नोड का नाम।

संदेश भेजने और प्राप्त करने

C नोड erl_receive msg() कॉल करके erl_receive msg() से संदेश प्राप्त कर सकते हैं। यह फ़ंक्शन ओपन फाइल डिस्क्रिप्टर fd से डेटा को एक बफर में पढ़ता है और परिणाम को एक ErlMessage स्ट्रक्चर emsg में डालता है। ErlMessage में एक फ़ील्ड type है जो यह ErlMessage है कि किस प्रकार का डेटा प्राप्त किया गया है। इस मामले में, ब्याज का प्रकार ERL_REG_SEND जो इंगित करता है कि ERL_REG_SEND ने सी नोड पर एक पंजीकृत प्रक्रिया को एक संदेश भेजा था। एक संदेश, वास्तविक संदेश, msg फ़ील्ड में है।

ERL_ERROR (एक त्रुटि उत्पन्न हुई) और ERL_TICK (अन्य नोड से ज़िंदा जाँच) को ध्यान में रखना आवश्यक है। अन्य संभावित प्रकार लिंक, अनलिंक और बाहर निकलने जैसी प्रक्रिया की घटनाओं का संकेत देते हैं:

while (loop) {

  got = erl_receive_msg(fd, buf, BUFSIZE, &emsg);
  if (got == ERL_TICK) {
    /* ignore */
  } else if (got == ERL_ERROR) {
    loop = 0; /* exit while loop */
  } else {
    if (emsg.type == ERL_REG_SEND) {

चूंकि संदेश एक ETERM संरचना है, इसलिए इसे हेरफेर करने के लिए Erl_Interface फ़ंक्शन का उपयोग किया जा सकता है। इस स्थिति में, संदेश 3-ट्यूपल बन जाता है, क्योंकि इसी तरह से एरलांग कोड लिखा जाता है। दूसरा तत्व कॉल करने वाले का पिड होगा और तीसरा तत्व टपल {Function,Arg} जो यह निर्धारित करेगा कि किस फ़ंक्शन को कॉल करना है, और किस तर्क के साथ। फ़ंक्शन को कॉल करने का नतीजा एक ETERM संरचना में बनाया गया है और erl_send() का उपयोग करके erl_send() को वापस भेज दिया गया है, जो ओपन फाइल डिस्क्रिप्टर, एक पीआईडी ​​और तर्कों के रूप में एक शब्द लेता है:

fromp = erl_element(2, emsg.msg);
tuplep = erl_element(3, emsg.msg);
fnp = erl_element(1, tuplep);
argp = erl_element(2, tuplep);

if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) {
  res = foo(ERL_INT_VALUE(argp));
} else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 3) == 0) {
  res = bar(ERL_INT_VALUE(argp));
}

resp = erl_format("{cnode, ~i}", res);
erl_send(fd, fromp, resp);

अंत में, ETERM द्वारा फ़ंक्शन ( erl_receive_msg() सहित निर्माण कार्य द्वारा आवंटित की गई मेमोरी को मुक्त किया जाना चाहिए:

erl_free_term(emsg.from); erl_free_term(emsg.msg);
erl_free_term(fromp); erl_free_term(tuplep);
erl_free_term(fnp); erl_free_term(argp);
erl_free_term(resp);

निम्न उदाहरण परिणामी C प्रोग्राम दिखाते हैं। पहले एक नोड नोड का उपयोग कर छोटा नोड नाम:

/* cnode_s.c */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include "erl_interface.h"
#include "ei.h"

#define BUFSIZE 1000

int main(int argc, char **argv) {
  int port;                                /* Listen port number */
  int listen;                              /* Listen socket */
  int fd;                                  /* fd to Erlang node */
  ErlConnect conn;                         /* Connection data */

  int loop = 1;                            /* Loop flag */
  int got;                                 /* Result of receive */
  unsigned char buf[BUFSIZE];              /* Buffer for incoming message */
  ErlMessage emsg;                         /* Incoming message */

  ETERM *fromp, *tuplep, *fnp, *argp, *resp;
  int res;

  port = atoi(argv[1]);

  erl_init(NULL, 0);

  if (erl_connect_init(1, "secretcookie", 0) == -1)
    erl_err_quit("erl_connect_init");

  /* Make a listen socket */
  if ((listen = my_listen(port)) <= 0)
    erl_err_quit("my_listen");

  if (erl_publish(port) == -1)
    erl_err_quit("erl_publish");

  if ((fd = erl_accept(listen, &conn)) == ERL_ERROR)
    erl_err_quit("erl_accept");
  fprintf(stderr, "Connected to %s\n\r", conn.nodename);

  while (loop) {

    got = erl_receive_msg(fd, buf, BUFSIZE, &emsg);
    if (got == ERL_TICK) {
      /* ignore */
    } else if (got == ERL_ERROR) {
      loop = 0;
    } else {

      if (emsg.type == ERL_REG_SEND) {
	fromp = erl_element(2, emsg.msg);
	tuplep = erl_element(3, emsg.msg);
	fnp = erl_element(1, tuplep);
	argp = erl_element(2, tuplep);

	if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) {
	  res = foo(ERL_INT_VALUE(argp));
	} else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 3) == 0) {
	  res = bar(ERL_INT_VALUE(argp));
	}

	resp = erl_format("{cnode, ~i}", res);
	erl_send(fd, fromp, resp);

	erl_free_term(emsg.from); erl_free_term(emsg.msg);
	erl_free_term(fromp); erl_free_term(tuplep);
	erl_free_term(fnp); erl_free_term(argp);
	erl_free_term(resp);
      }
    }
  } /* while */
}

  
int my_listen(int port) {
  int listen_fd;
  struct sockaddr_in addr;
  int on = 1;

  if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    return (-1);

  setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

  memset((void*) &addr, 0, (size_t) sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);
  addr.sin_addr.s_addr = htonl(INADDR_ANY);

  if (bind(listen_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
    return (-1);

  listen(listen_fd, 5);
  return listen_fd;
}

एसी नोड सर्वर लंबे नोड नाम का उपयोग कर:

/* cnode_s2.c */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include "erl_interface.h"
#include "ei.h"

#define BUFSIZE 1000

int main(int argc, char **argv) {
  struct in_addr addr;                     /* 32-bit IP number of host */
  int port;                                /* Listen port number */
  int listen;                              /* Listen socket */
  int fd;                                  /* fd to Erlang node */
  ErlConnect conn;                         /* Connection data */

  int loop = 1;                            /* Loop flag */
  int got;                                 /* Result of receive */
  unsigned char buf[BUFSIZE];              /* Buffer for incoming message */
  ErlMessage emsg;                         /* Incoming message */

  ETERM *fromp, *tuplep, *fnp, *argp, *resp;
  int res;
  
  port = atoi(argv[1]);

  erl_init(NULL, 0);

  addr.s_addr = inet_addr("134.138.177.89");
  if (erl_connect_xinit("idril", "cnode", "[email protected]",
			&addr, "secretcookie", 0) == -1)
    erl_err_quit("erl_connect_xinit");

  /* Make a listen socket */
  if ((listen = my_listen(port)) <= 0)
    erl_err_quit("my_listen");

  if (erl_publish(port) == -1)
    erl_err_quit("erl_publish");

  if ((fd = erl_accept(listen, &conn)) == ERL_ERROR)
    erl_err_quit("erl_accept");
  fprintf(stderr, "Connected to %s\n\r", conn.nodename);

  while (loop) {

    got = erl_receive_msg(fd, buf, BUFSIZE, &emsg);
    if (got == ERL_TICK) {
      /* ignore */
    } else if (got == ERL_ERROR) {
      loop = 0;
    } else {

      if (emsg.type == ERL_REG_SEND) {
	fromp = erl_element(2, emsg.msg);
	tuplep = erl_element(3, emsg.msg);
	fnp = erl_element(1, tuplep);
	argp = erl_element(2, tuplep);

	if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) {
	  res = foo(ERL_INT_VALUE(argp));
	} else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 3) == 0) {
	  res = bar(ERL_INT_VALUE(argp));
	}

	resp = erl_format("{cnode, ~i}", res);
	erl_send(fd, fromp, resp);

	erl_free_term(emsg.from); erl_free_term(emsg.msg);
	erl_free_term(fromp); erl_free_term(tuplep);
	erl_free_term(fnp); erl_free_term(argp);
	erl_free_term(resp);
      }
    }
  }
}

  
int my_listen(int port) {
  int listen_fd;
  struct sockaddr_in addr;
  int on = 1;

  if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    return (-1);

  setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

  memset((void*) &addr, 0, (size_t) sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);
  addr.sin_addr.s_addr = htonl(INADDR_ANY);

  if (bind(listen_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
    return (-1);

  listen(listen_fd, 5);
  return listen_fd;
}

अंत में, C नोड क्लाइंट के लिए कोड:

/* cnode_c.c */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include "erl_interface.h"
#include "ei.h"

#define BUFSIZE 1000

int main(int argc, char **argv) {
  int fd;                                  /* fd to Erlang node */

  int loop = 1;                            /* Loop flag */
  int got;                                 /* Result of receive */
  unsigned char buf[BUFSIZE];              /* Buffer for incoming message */
  ErlMessage emsg;                         /* Incoming message */

  ETERM *fromp, *tuplep, *fnp, *argp, *resp;
  int res;
  
  erl_init(NULL, 0);

  if (erl_connect_init(1, "secretcookie", 0) == -1)
    erl_err_quit("erl_connect_init");

  if ((fd = erl_connect("[email protected]")) < 0)
    erl_err_quit("erl_connect");
  fprintf(stderr, "Connected to [email protected]\n\r");

  while (loop) {

    got = erl_receive_msg(fd, buf, BUFSIZE, &emsg);
    if (got == ERL_TICK) {
      /* ignore */
    } else if (got == ERL_ERROR) {
      loop = 0;
    } else {

      if (emsg.type == ERL_REG_SEND) {
	fromp = erl_element(2, emsg.msg);
	tuplep = erl_element(3, emsg.msg);
	fnp = erl_element(1, tuplep);
	argp = erl_element(2, tuplep);

	if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) {
	  res = foo(ERL_INT_VALUE(argp));
	} else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 3) == 0) {
	  res = bar(ERL_INT_VALUE(argp));
	}

	resp = erl_format("{cnode, ~i}", res);
	erl_send(fd, fromp, resp);

	erl_free_term(emsg.from); erl_free_term(emsg.msg);
	erl_free_term(fromp); erl_free_term(tuplep);
	erl_free_term(fnp); erl_free_term(argp);
	erl_free_term(resp);
      }
    }
  }
}

7.3 उदाहरण रनिंग

चरण 1. सी कोड संकलित करें। यह Erl_Interface के लिए पथ प्रदान करता है जिसमें फ़ाइलें और पुस्तकालय और socket और nsl लाइब्रेरी शामिल हैं:

>  gcc -o cserver \\
-I/usr/local/otp/lib/erl_interface-3.2.1/include \\
-L/usr/local/otp/lib/erl_interface-3.2.1/lib \\
complex.c cnode_s.c \\
-lerl_interface -lei -lsocket -lnsl

unix> gcc -o cserver2 \\
-I/usr/local/otp/lib/erl_interface-3.2.1/include \\
-L/usr/local/otp/lib/erl_interface-3.2.1/lib \\
complex.c cnode_s2.c \\
-lerl_interface -lei -lsocket -lnsl

unix> gcc -o cclient \\
-I/usr/local/otp/lib/erl_interface-3.2.1/include \\
-L/usr/local/otp/lib/erl_interface-3.2.1/lib \\
complex.c cnode_c.c \\
-lerl_interface -lei -lsocket -lnsl

Erlang / OTP R5B और OTP के बाद के संस्करणों में, OTPROOT/lib/erl_interface-VSN अंतर्गत include और OTPROOT/lib/erl_interface-VSN निर्देशिकाएँ स्थित हैं, जहाँ OTPROOT हाल के उदाहरण में OTP स्थापना ( /usr/local/otp ) की मूल निर्देशिका है और VSN Erl_Interface एप्लिकेशन (हाल के उदाहरण में 3.2.1) का संस्करण है।

R4B और OTP के पुराने संस्करणों में, include और lib OTPROOT/usr अंतर्गत स्थित हैं।

चरण 2. Erlang कोड संकलित करें:

unix> erl -compile complex3 complex4

चरण 3. लघु नोड नामों के साथ C नोड सर्वर उदाहरण चलाएँ।

निम्नानुसार करें:

  • अलग-अलग विंडो में C प्रोग्राम cserver और Erlang शुरू करें।
  • cserver तर्क के रूप में एक पोर्ट नंबर लेता है और Erlang फ़ंक्शन को कॉल करने का प्रयास करने से पहले प्रारंभ किया जाना चाहिए।
  • Erlang नोड को संक्षिप्त नाम e1 दिया जाना है और C नोड, secretcookie के समान मैजिक कुकी का उपयोग करने के लिए सेट किया जाना चाहिए:
unix> cserver 3456

unix> erl -sname e1 -setcookie secretcookie
Erlang (BEAM) emulator version 4.9.1.2
 
Eshell V4.9.1.2  (abort with ^G)
([email protected])1> complex3:foo(3).
4
([email protected])2> complex3:bar(5).
10

चरण 4. सी नोड क्लाइंट उदाहरण चलाएँ। cserver समाप्त cserver , लेकिन cserver नहीं, और cclient शुरू cclient । Erlang नोड को C नोड क्लाइंट से पहले शुरू किया जाना चाहिए:

unix> cclient

([email protected])3> complex3:foo(3).
4
([email protected])4> complex3:bar(5).
10

चरण 5. लंबे नोड नामों के साथ C नोड सर्वर उदाहरण चलाएँ:

unix> cserver2 3456

unix> erl -name e1 -setcookie secretcookie
Erlang (BEAM) emulator version 4.9.1.2
 
Eshell V4.9.1.2  (abort with ^G)
([email protected])1> complex4:foo(3).
4
([email protected])2> complex4:bar(5).
10