Erlang 21 - 1. Erl_Interface User's Guide

1 Erl_Interface उपयोगकर्ता की मार्गदर्शिका




erlang

1 Erl_Interface उपयोगकर्ता की मार्गदर्शिका

१.१ परिचय

Erl_Interface लाइब्रेरी में फ़ंक्शंस होते हैं जो आपको C और Erlang में लिखे प्रोग्राम को एकीकृत करने में मदद करते हैं। Erl_Interface में कार्य निम्नलिखित का समर्थन करते हैं:

  • Erlang डेटा प्रकारों के रूप में प्रतिनिधित्व डेटा का हेरफेर
  • C और Erlang स्वरूपों के बीच डेटा का रूपांतरण
  • ट्रांसमिशन या भंडारण के लिए एरलंग डेटा प्रकारों का एन्कोडिंग और डिकोडिंग
  • सी नोड्स और एरलंग प्रक्रियाओं के बीच संचार
  • Mnesia लिए और से C नोड स्थिति का बैकअप और पुनर्स्थापना
ध्यान दें

डिफ़ॉल्ट रूप से, Erl_Interface लाइब्रेरीज़ को केवल लाइब्रेरी के अन्य रिलीज़ से अन्य Erlang / OTP घटकों के साथ संगत होने की गारंटी है। पूर्व रिलीज़ से Erlang / OTP घटकों के साथ संवाद करने के तरीके के बारे में जानकारी के लिए, फ़ंक्शन देखें ei:ei_set_compat_rel और erl_eterm:erl_set_compat_rel

क्षेत्र

निम्नलिखित वर्गों में, इन विषयों का वर्णन किया गया है:

  • Erl_Interface साथ उपयोग के लिए अपने कोड का संकलन
  • प्रारंभिक Erl_Interface
  • एन्कोडिंग, डीकोडिंग और इरलांग शब्द भेजना
  • भवन की शर्तें और पैटर्न
  • पैटर्न मिलान
  • एक वितरित एर्लांग नोड से कनेक्ट करना
  • एर्लैंग पोर्ट मैपर डेमन (EPMD) का उपयोग करना
  • Erlang संदेश भेजना और प्राप्त करना
  • दूरस्थ प्रक्रिया कॉल
  • वैश्विक नामों का उपयोग करना
  • रजिस्ट्री का उपयोग करना

आवश्यक शर्तें

यह माना जाता है कि पाठक एरलांग प्रोग्रामिंग भाषा से परिचित है।

1.2 आपका कोड संकलित करना और जोड़ना

किसी भी Erl_Interface फ़ंक्शंस का उपयोग करने के लिए, अपने कोड में निम्न पंक्तियाँ शामिल करें:

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

निर्धारित करें कि आपकी OTP स्थापना की शीर्ष निर्देशिका कहां है। इसे खोजने के लिए, Erlang शुरू करें और Eshell प्रॉम्प्ट पर निम्नलिखित कमांड दर्ज करें:

Eshell V4.7.4  (abort with ^G)
1> code:root_dir().
/usr/local/otp    

अपने कोड को संकलित करने के लिए, सुनिश्चित करें कि आपका सी कंपाइलर जानता है कि कमांड लाइन पर एक उपयुक्त -I तर्क निर्दिष्ट करके, या अपने Makefile में CFLAGS परिभाषा में erl_interface.h को कहां खोजें। इस मार्ग का सही मूल्य $OTPROOT/lib/erl_interface-$EIVSN/include , जहां:

  • $OTPROOT code:root_dir/0 द्वारा बताया गया पथ है code:root_dir/0 उपरोक्त उदाहरण में।

  • $EIVSN Erl_Interface एप्लिकेशन का संस्करण है, उदाहरण के लिए, erl_interface-3.2.3

कोड संकलित करना:

$ cc -c -I/usr/local/otp/lib/erl_interface-3.2.3/include myprog.c    

लिंक करते समय:

  • liberl_interface.a और libei.a साथ -L$OTPROOT/lib/erl_interface-3.2.3/lib लिए पथ निर्दिष्ट करें।
  • पुस्तकालयों का नाम -lerl_interface -lei साथ निर्दिष्ट करें।

कमांड लाइन पर ऐसा करें या अपने LDFLAGS में LDFLAGS परिभाषा में झंडे जोड़ें।

कोड जोड़ना:

$ ld -L/usr/local/otp/lib/erl_interface-3.2.3/
                            lib myprog.o -lerl_interface -lei -o myprog    

कुछ सिस्टम पर wsock32.lib की संचार सुविधाओं का उपयोग करने के लिए कुछ और पुस्तकालयों (उदाहरण के लिए, libnsl.a और libsocket.a पर Solaris, या wsock32.lib पर विंडोज) के साथ लिंक करना आवश्यक हो सकता है।

यदि आप POSIX थ्रेड्स या सोलारिस थ्रेड्स के आधार पर थ्रेडेड एप्लिकेशन में Erl_Interface फ़ंक्शंस का उपयोग करते हैं, तो Erl_Interface को आपके थ्रेड पैकेज में कुछ सिंक्रनाइज़ेशन सुविधाओं तक पहुंच की आवश्यकता होती है। आपके द्वारा उपयोग किए जाने वाले पैकेजों को इंगित करने के लिए आपको अतिरिक्त संकलक झंडे निर्दिष्ट करने होंगे। _REENTRANT और या तो STHREADS या _REENTRANT परिभाषित करें। यदि डिफ़ॉल्ट निर्दिष्ट है, तो डिफ़ॉल्ट POSIX थ्रेड का उपयोग _REENTRANT है।

1.3 एर्ल_इंटरफेस लाइब्रेरी की शुरुआत

किसी भी अन्य Erl_Interface फ़ंक्शन को कॉल करने से पहले, लाइब्रेरी को आरंभ करने के लिए erl_init() एक बार कॉल करें। erl_init() दो तर्क लेता है। हालाँकि, तर्क अब Erl_Interface द्वारा उपयोग नहीं किए Erl_Interface और इसलिए erl_init(NULL,0) रूप में निर्दिष्ट किया erl_init(NULL,0)

1.4 एन्कोडिंग, डिकोडिंग, और इरलंग शब्द भेजना

वितरित एर्लैंग नोड्स के बीच भेजा गया डेटा एरलैंग बाहरी प्रारूप में एन्कोड किया गया है। इसलिए आपको बाइट धाराओं में एर्लैंग की शर्तों को एनकोड और डीकोड करना होगा यदि आप सी प्रोग्राम और एर्लैंग के बीच संवाद करने के लिए वितरण प्रोटोकॉल का उपयोग करना चाहते हैं।

Erl_Interface लाइब्रेरी इस गतिविधि का समर्थन करती है। इसमें कई C फ़ंक्शन हैं जो Erlang डेटा संरचनाओं का निर्माण और हेरफेर करते हैं। पुस्तकालय में एक एनकोड और एक डिकोड फ़ंक्शन भी होता है। निम्न उदाहरण दिखाता है कि {tobbe,3928} टपल {tobbe,3928} को कैसे बनाया और एनकोड किया {tobbe,3928} :

ETERM *arr[2], *tuple;
char buf[BUFSIZ];
int i;
  
arr[0] = erl_mk_atom("tobbe");
arr[1] = erl_mk_integer(3928);
tuple  = erl_mk_tuple(arr, 2);
i = erl_encode(tuple, buf);    

वैकल्पिक रूप से, आप erl_send() और erl_receive_msg उपयोग कर सकते हैं, जो पारदर्शी रूप से संदेशों के एन्कोडिंग और डिकोडिंग को संभालते हैं।

पूर्ण विवरण के लिए, निम्न मॉड्यूल देखें:

  • Erlang शब्द बनाने के लिए erl_eterm
  • एन्कोडिंग और डिकोडिंग रूटीन के लिए erl_marshal

1.5 भवन की शर्तें और पैटर्न

Erlang शब्द बनाने के लिए erl_format मॉड्यूल का उपयोग करके पिछले उदाहरण को सरल बनाया जा सकता है:

ETERM *ep;
ep = erl_format("{~a,~i}", "tobbe", 3928);    

विभिन्न प्रारूप निर्देशों के पूर्ण विवरण के लिए, erl_format मॉड्यूल देखें।

निम्नलिखित उदाहरण अधिक जटिल है:

ETERM *ep;
ep = erl_format("[{name,~a},{age,~i},{data,~w}]",
                 "madonna", 
                 21, 
                 erl_format("[{adr,~s,~i}]", "E-street", 42));
erl_free_compound(ep);      

पिछले उदाहरणों की तरह, यह आपकी ज़िम्मेदारी है कि एरलांग की शर्तों के लिए आवंटित स्मृति को मुक्त करें। इस उदाहरण में, erl_free_compound() सुनिश्चित करता है कि पूर्ण अवधि के लिए इंगित किया गया शब्द जारी किया गया है। यह आवश्यक है क्योंकि सूचक दूसरी कॉल से erl_format खो जाता है।

निम्नलिखित उदाहरण थोड़ा अलग समाधान दिखाता है:

ETERM *ep,*ep2;
ep2 = erl_format("[{adr,~s,~i}]","E-street",42);
ep  = erl_format("[{name,~a},{age,~i},{data,~w}]",
                 "madonna", 21, ep2);
erl_free_term(ep);  
erl_free_term(ep2);      

इस मामले में, आप दो शब्दों को स्वतंत्र रूप से मुक्त करते हैं। जिस क्रम में आप शब्द ep और ep2 को मुक्त करते हैं वह महत्वपूर्ण नहीं है, क्योंकि Erl_Interface लाइब्रेरी Erl_Interface गिनती को सुरक्षित करने के लिए निर्धारित करने के लिए संदर्भ गिनती का उपयोग करती है।

यदि आप अनिश्चित हैं कि क्या आपने शर्तों को ठीक से मुक्त किया है, तो आप निश्चित अवधि के आवंटनकर्ता की स्थिति देखने के लिए निम्न फ़ंक्शन का उपयोग कर सकते हैं:

long allocated, freed;

erl_eterm_statistics(&allocated,&freed);
printf("currently allocated blocks: %ld\n",allocated);
printf("length of freelist: %ld\n",freed);

/* really free the freelist */
erl_eterm_release();

अधिक जानकारी के लिए, erl_malloc मॉड्यूल देखें।

1.6 पैटर्न मिलान

एरलैंग पैटर्न एक ऐसा शब्द है जिसमें अनबाउंड वैरिएबल हो सकते हैं या प्रतीकों की "do not care" । इस तरह के पैटर्न को एक शब्द के खिलाफ मिलान किया जा सकता है और, यदि मैच सफल होता है, तो पैटर्न में कोई भी अनबाउंड चर साइड इफेक्ट के रूप में बाध्य होगा। एक बाध्य चर की सामग्री को फिर से प्राप्त किया जा सकता है:

ETERM *pattern;
pattern = erl_format("{madonna,Age,_}");    

erl_format:erl_match फ़ंक्शन पैटर्न से मेल खाता है। यह एक पैटर्न और एक शब्द लेता है और उनसे मेल खाने की कोशिश करता है। साइड इफेक्ट के रूप में पैटर्न में कोई भी अनबाउंड वैरिएबल बाध्य होगा। निम्नलिखित उदाहरण में, एक पैटर्न एक चर Age के साथ बनाया जाता है, जिसे टपल में दो पदों पर शामिल किया गया है। पैटर्न मिलान निम्नानुसार किया जाता है:

  • erl_match पहली बार चर तक पहुंचने वाली Age की सामग्री को 21 से बांधता है।

  • Age की दूसरी घटना में शब्दों के बीच समानता के लिए एक परीक्षण का कारण बनता है, क्योंकि Age पहले से ही 21 से बंधी है। जैसे-जैसे Age 21 , समानता परीक्षण सफल होता है और पैटर्न के अंत तक मैच जारी रहता है।

  • यदि पैटर्न का अंत हो गया है, तो मैच सफल होता है और आप चर की सामग्री को पुनः प्राप्त कर सकते हैं।

ETERM *pattern,*term;
pattern = erl_format("{madonna,Age,Age}");
term    = erl_format("{madonna,21,21}");
if (erl_match(pattern, term)) {
  fprintf(stderr, "Yes, they matched: Age = ");
  ep = erl_var_content(pattern, "Age"); 
  erl_print_term(stderr, ep);
  fprintf(stderr,"\n");
  erl_free_term(ep);
}
erl_free_term(pattern);
erl_free_term(term);    

अधिक जानकारी के लिए, erl_format:erl_match फ़ंक्शन देखें।

1.7 एक वितरित एर्लांग नोड से कनेक्ट होना

वितरित एर्लैंग नोड से कनेक्ट करने के लिए, आपको पहले कनेक्शन रूटीन को erl_connect:erl_connect_init साथ प्रारंभ करना होगा erl_connect:erl_connect_init , जो जानकारी संग्रहीत करता है, जैसे होस्टनाम, नोड नाम और बाद के उपयोग के लिए आईपी पता:

int identification_number = 99;
int creation=1;
char *cookie="a secret cookie string"; /* An example */
erl_connect_init(identification_number, cookie, creation);    

अधिक जानकारी के लिए, erl_connect मॉड्यूल देखें।

आरंभीकरण के बाद, आप एरलंग नोड से संबंध स्थापित करते हैं। उस Erlang नोड को निर्दिष्ट करने के लिए जिसे आप कनेक्ट करना चाहते हैं, erl_connect() उपयोग करें। निम्न उदाहरण कनेक्शन सेट करता है और एक मान्य सॉकेट फ़ाइल डिस्क्रिप्टर में परिणाम होता है:

int sockfd;
char *nodename="[email protected]"; /* An example */
if ((sockfd = erl_connect(nodename)) < 0)
  erl_err_quit("ERROR: erl_connect failed");    

erl_err_quit() निर्दिष्ट स्ट्रिंग को प्रिंट करता है और प्रोग्राम को समाप्त करता है। अधिक जानकारी के लिए, erl_error मॉड्यूल देखें।

1.8 EPMD का उपयोग करना

erts:epmd Erlang Port Mapper Daemon है। वितरित Erlang नोड्स स्थानीय होस्ट पर epmd साथ रजिस्टर करते हैं ताकि वे अन्य नोड्स को इंगित कर सकें कि वे मौजूद हैं और कनेक्शन स्वीकार कर सकते हैं। epmd नोड और पोर्ट नंबर की जानकारी का एक रजिस्टर रखता है, और जब एक नोड दूसरे नोड से कनेक्ट करना चाहता है, तो यह कनेक्ट करने के लिए सही पोर्ट नंबर खोजने के लिए पहले epmd से संपर्क epmd है।

जब आप Erlang नोड से कनेक्ट करने के लिए erl_connect का उपयोग करते हैं, तो सबसे पहले एक कनेक्शन epmd बनाया जाता है और, यदि नोड ज्ञात होता है, तो एक कनेक्शन फिर Erlang नोड में किया जाता है।

यदि वे चाहते हैं कि सिस्टम के अन्य नोड्स उन्हें खोजने और उनसे जुड़ने में सक्षम हों तो C नोड्स भी epmd साथ खुद को पंजीकृत कर सकते हैं।

epmd साथ पंजीकरण करने से पहले, आपको पहले एक सॉकेट बनाना होगा और इसे एक पोर्ट से बांधना होगा। फिर:

int pub;

pub = erl_publish(port);    

pub एक फ़ाइल विवरणक है जो अब epmd जुड़ा है। epmd कनेक्शन के दूसरे छोर पर नज़र रखता है। यदि यह पता लगाता है कि कनेक्शन बंद कर दिया गया है, तो नोड अपंजीकृत हो जाता है। इसलिए, यदि आप स्पष्ट रूप से डिस्क्रिप्टर को बंद करते हैं या यदि आपका नोड विफल रहता है, तो यह epmd से अपंजीकृत हो जाता है।

ध्यान दें कि कुछ सिस्टम (जैसे VxWorks) पर, इस तंत्र द्वारा एक विफल नोड का पता नहीं लगाया जाता है, क्योंकि ऑपरेटिंग सिस्टम स्वचालित रूप से उन डिस्क्रिप्टर को बंद नहीं करता है जो नोड के विफल होने पर खुले छोड़ दिए गए थे। यदि एक नोड इस तरह से विफल हो गया है, तो epmd आपको पुराने नाम के साथ एक नया नोड दर्ज करने से रोकता है, क्योंकि यह सोचता है कि पुराना नाम अभी भी उपयोग में है। इस स्थिति में, आपको नाम स्पष्ट रूप से अनरजिस्टर्ड करना होगा:

erl_unpublish(node);    

यह epmd को दूर के अंत से कनेक्शन बंद करने का कारण बनता है। ध्यान दें कि यदि नाम वास्तव में अभी भी एक नोड द्वारा उपयोग में था, तो इस ऑपरेशन के परिणाम अप्रत्याशित हैं। इसके अलावा, ऐसा करने से कनेक्शन का स्थानीय अंत बंद नहीं होता है, इसलिए संसाधनों का उपभोग किया जा सकता है।

1.9 एरलांग संदेश भेजना और प्राप्त करना

संदेश भेजने के लिए निम्नलिखित दो कार्यों में से एक का उपयोग करें:

जैसा कि एर्लांग में, संदेशों को एक पिड या एक पंजीकृत नाम पर भेजा जा सकता है। एक पंजीकृत नाम पर एक संदेश भेजना आसान है, क्योंकि यह एक उपयुक्त पिड खोजने की समस्या से बचा जाता है।

संदेश प्राप्त करने के लिए निम्नलिखित दो कार्यों में से एक का उपयोग करें:

erl_receive() संदेश को एक बफर में प्राप्त करता है, जबकि erl_receive_msg() संदेश को Erlang शब्द में डिकोड करता है।

संदेश भेजने का उदाहरण

निम्न उदाहरण में, {Pid, hello_world} को एक पंजीकृत प्रक्रिया my_server भेजा जाता है। संदेश erl_send() द्वारा एन्कोड किया erl_send() :

extern const char *erl_thisnodename(void);
extern short erl_thiscreation(void);
#define SELF(fd) erl_mk_pid(erl_thisnodename(),fd,0,erl_thiscreation())
ETERM *arr[2], *emsg;
int sockfd, creation=1;
  
arr[0] = SELF(sockfd);
arr[1] = erl_mk_atom("Hello world");
emsg   = erl_mk_tuple(arr, 2);
  
erl_reg_send(sockfd, "my_server", emsg);
erl_free_term(emsg);      

टपल का पहला तत्व जो भेजा जाता है वह आपका अपना पिड होता है। यह my_server को उत्तर देने में सक्षम बनाता है। आदिम के बारे में अधिक जानकारी के लिए, erl_connect मॉड्यूल देखें।

संदेश प्राप्त करने का उदाहरण

इस उदाहरण में, {Pid, Something} प्राप्त होता है। प्राप्त पीड का उपयोग तब {goodbye,Pid} पिड {goodbye,Pid} को वापस करने के लिए किया जाता है।

ETERM *arr[2], *answer;
int sockfd,rc;
char buf[BUFSIZE];
ErlMessage emsg;
  
if ((rc = erl_receive_msg(sockfd , buf, BUFSIZE, &emsg)) == ERL_MSG) {
   arr[0] = erl_mk_atom("goodbye");
   arr[1] = erl_element(1, emsg.msg); 
   answer = erl_mk_tuple(arr, 2);
   erl_send(sockfd, arr[1], answer);
   erl_free_term(answer);
   erl_free_term(emsg.msg);
   erl_free_term(emsg.to);
}      

मजबूती प्रदान करने के लिए, एक वितरित एर्लैंग नोड कभी-कभी विफल नोड्स या संचार लिंक का पता लगाने के प्रयास में अपने सभी जुड़े पड़ोसियों को मतदान करता है। ऐसा संदेश प्राप्त करने वाले नोड को ERL_TICK संदेश के साथ तुरंत प्रतिक्रिया देने की अपेक्षा की जाती है। यह स्वचालित रूप से erl_receive() द्वारा किया जाता है। हालाँकि, जब ऐसा हुआ है, तो ErlMessage संरचना में कोई संदेश संग्रहीत किए बिना कॉल करने वाले को ErlMessage

जब कोई संदेश प्राप्त हुआ है, तो प्राप्त संदेश के प्रकार के आधार पर, प्राप्त संदेश emsg.msg और emsg.to या emsg.from को मुक्त करना कॉलर की जिम्मेदारी है।

अधिक जानकारी के लिए, erl_connect और erl_eterm मॉड्यूल देखें।

1.10 दूरस्थ प्रक्रिया कॉल

एक Erlang नोड एक और Erlang नोड के लिए एक ग्राहक के रूप में कार्य आमतौर पर एक अनुरोध भेजता है और एक उत्तर के लिए प्रतीक्षा करता है। इस तरह के अनुरोध को रिमोट नोड पर एक फ़ंक्शन कॉल में शामिल किया जाता है और इसे दूरस्थ प्रक्रिया कॉल कहा जाता है।

निम्न उदाहरण दिखाता है कि Erl_Interface लाइब्रेरी दूरस्थ प्रक्रिया कॉल का समर्थन कैसे करती है:

char modname[]=THE_MODNAME;
ETERM *reply,*ep;
ep = erl_format("[~a,[]]", modname);
if (!(reply = erl_rpc(fd, "c", "c", ep)))
  erl_err_msg("<ERROR> when compiling file: %s.erl !\n", modname);
erl_free_term(ep);
ep = erl_format("{ok,_}");
if (!erl_match(ep, reply))
  erl_err_msg("<ERROR> compiler errors !\n");
erl_free_term(ep);
erl_free_term(reply);    

c:c/1 को दूरस्थ नोड पर निर्दिष्ट मॉड्यूल संकलित करने के लिए कहा जाता है। erl_match() जांचता है कि अपेक्षित ok लिए परीक्षण द्वारा संकलन सफल रहा।

erl_rpc() और उसके साथी erl_rpc_to() और erl_rpc_from() बारे में अधिक जानकारी के लिए, erl_connect मॉड्यूल देखें।

1.11 वैश्विक नामों का उपयोग करना

एसी नोड के पास कर्नेल में global मॉड्यूल के माध्यम से पंजीकृत नामों तक पहुंच है। नामों को देखा जा सकता है, जिससे सी नोड को एर्लांग सेवाओं के नाम संदेश भेजने की अनुमति मिलती है। सी नोड्स वैश्विक नामों को भी पंजीकृत कर सकते हैं, जिससे उन्हें एरलांग प्रक्रियाओं या अन्य सी नोड्स को नामित सेवाएं प्रदान करने की अनुमति मिलती है।

Erl_Interface वैश्विक सेवा का मूल कार्यान्वयन प्रदान नहीं करता है। इसके बजाय यह "पास" एर्लांग नोड द्वारा प्रदान की गई वैश्विक सेवाओं का उपयोग करता है। इस खंड में वर्णित सेवाओं का उपयोग करने के लिए, पहले एक एरलंग नोड से कनेक्शन खोलना आवश्यक है।

यह देखने के लिए कि क्या नाम हैं:

char **names;
int count;
int i;

names = erl_global_names(fd,&count);

if (names) 
  for (i=0; i<count; i++) 
    printf("%s\n",names[i]);

free(names);    

erl_global:erl_global_names आवंटित करता है और Kernel में global मॉड्यूल के लिए ज्ञात सभी नामों से युक्त एक बफर लौटाता है। सरणी में नामों की संख्या को इंगित करने के लिए count आरम्भिक है। नामों में तार के सरणी को NULL पॉइंटर द्वारा समाप्त किया जाता है, इसलिए अंतिम नाम पहुंचने पर यह निर्धारित करने के लिए count का उपयोग करना आवश्यक नहीं है।

यह सरणी को मुक्त करने के लिए कॉलर की जिम्मेदारी है। erl_global_names सरणी को आवंटित करता है और erl_global_names malloc() लिए एक एकल कॉल का उपयोग करके सभी तार, इसलिए free(names) सभी आवश्यक है।

नामों में से एक को देखने के लिए:

ETERM *pid;
char node[256];

pid = erl_global_whereis(fd,"schedule",node);    

यदि "schedule" को Kernel में global मॉड्यूल के लिए जाना जाता है, तो एक एर्लांग पिग लौटाया जाता है जिसका उपयोग शेड्यूल सेवा में संदेश भेजने के लिए किया जा सकता है। इसके अलावा, node को उस नोड का नाम शामिल करने के लिए आरंभीकृत किया जाता है, जहां सेवा पंजीकृत है, ताकि आप केवल erl_connect करने के लिए चर को पास करके इससे एक संबंध बना erl_connect

नाम दर्ज करने से पहले, आपको पहले से ही अपना पोर्ट नंबर दर्ज करना चाहिए। यह कड़ाई से आवश्यक नहीं है, लेकिन यदि आप ऐसा करने के लिए उपेक्षा करते हैं, तो आपकी सेवा के साथ संवाद करने के इच्छुक अन्य नोड्स आपकी प्रक्रिया को ढूंढ या कनेक्ट नहीं कर सकते हैं।

अपनी सेवा के साथ संवाद करने के लिए Erlang प्रक्रियाओं का उपयोग कर सकते हैं एक पीड बनाएँ:

ETERM *pid;

pid = erl_mk_pid(thisnode,14,0,0);
erl_global_register(fd,servicename,pid);    

नाम दर्ज करने के बाद, आने वाले कनेक्शन की प्रतीक्षा करने के लिए erl_connect:erl_accept का उपयोग करें।

ध्यान दें

बाद में erl_malloc:erl_free_term साथ मुक्त करने के लिए याद रखें।

एक नाम अपंजीकृत करने के लिए:

erl_global_unregister(fd,servicename);    

1.12 रजिस्ट्री का उपयोग करना

यह खंड रजिस्ट्री के उपयोग का वर्णन करता है, सी-नोड में कुंजी-मूल्य जोड़े को संग्रहीत करने के लिए एक सरल तंत्र, साथ ही साथ उन्हें एक Mnesia नोड पर एक Mnesia तालिका से पुनर्स्थापित करने या पुनर्स्थापित करने के लिए। व्यक्तिगत API फ़ंक्शन के बारे में अधिक विस्तृत जानकारी के लिए, registry मॉड्यूल देखें।

कुंजी तार हैं, अर्थात्, वर्णों की पूर्ण-पृथक सारणियां और मान मनमानी वस्तुएं हैं। हालाँकि पूर्णांक और फ्लोटिंग पॉइंट नंबरों को रजिस्ट्री द्वारा विशेष रूप से व्यवहार किया जाता है, आप किसी भी प्रकार के स्ट्रिंग या बाइनरी ऑब्जेक्ट को पॉइंटर्स के रूप में स्टोर कर सकते हैं।

शुरू करने के लिए, एक रजिस्ट्री खोलें:

ei_reg *reg;

reg = ei_reg_open(45);    

उदाहरण में संख्या 45 ऑब्जेक्ट की अनुमानित संख्या को इंगित करता है जिसे आप रजिस्ट्री में संग्रहीत करने की अपेक्षा करते हैं। आंतरिक रूप से रजिस्ट्री हैशिंग तालिकाओं के साथ टकराव की श्रृंखला का उपयोग करती है, इसलिए रजिस्ट्री में उन वस्तुओं की संख्या पर कोई पूर्ण ऊपरी सीमा नहीं होती है, लेकिन यदि प्रदर्शन या मेमोरी का उपयोग महत्वपूर्ण है, तो आप तदनुसार संख्या का चयन कर सकते हैं। रजिस्ट्री को बाद में संशोधित किया जा सकता है।

आप जितने चाहें उतने रजिस्ट्रियां खोल सकते हैं (यदि मेमोरी परमिट हो)।

वस्तुओं को सेट के माध्यम से संग्रहीत और पुनर्प्राप्त किया जाता है और फ़ंक्शन प्राप्त होते हैं। निम्न उदाहरण दिखाता है कि पूर्णांक, फ़्लोट्स, स्ट्रिंग्स और मनमानी बाइनरी ऑब्जेक्ट्स को कैसे संग्रहीत किया जाए:

struct bonk *b = malloc(sizeof(*b));
char *name = malloc(7);

ei_reg_setival(reg,"age",29); 
ei_reg_setfval(reg,"height",1.85);

strcpy(name,"Martin");
ei_reg_setsval(reg,"name",name); 

b->l = 42;
b->m = 12;
ei_reg_setpval(reg,"jox",b,sizeof(*b));    

यदि आप रजिस्ट्री में किसी ऑब्जेक्ट को संग्रहीत करने का प्रयास करते हैं और उसी कुंजी के साथ एक मौजूदा ऑब्जेक्ट है, तो नया मान पुराने को बदल देता है। यह इस बात पर ध्यान दिए बिना किया जाता है कि क्या नई वस्तु और पुराने में एक ही प्रकार है, इसलिए, आप उदाहरण के लिए, एक स्ट्रिंग को पूर्णांक से बदल सकते हैं। यदि मौजूदा मान एक स्ट्रिंग या बाइनरी है, तो नए मूल्य को असाइन करने से पहले इसे मुक्त कर दिया जाता है।

संग्रहीत मान रजिस्ट्री से निम्नानुसार प्राप्त होते हैं:

long i;
double f;
char *s;
struct bonk *b;
int size;

i = ei_reg_getival(reg,"age");
f = ei_reg_getfval(reg,"height");
s = ei_reg_getsval(reg,"name");
b = ei_reg_getpval(reg,"jox",&size);    

उपरोक्त सभी उदाहरणों में, ऑब्जेक्ट मौजूद होना चाहिए और यह निर्दिष्ट ऑपरेशन के लिए सही प्रकार का होना चाहिए। यदि आपको किसी वस्तु का प्रकार नहीं पता है, तो आप पूछ सकते हैं:

struct ei_reg_stat buf;

ei_reg_stat(reg,"name",&buf);    

Buf को ऑब्जेक्ट विशेषताओं को शामिल करने के लिए प्रारंभ किया गया है।

रजिस्ट्री से वस्तुओं को हटाया जा सकता है:

ei_reg_delete(reg,"name");    

जब आप एक रजिस्ट्री के साथ समाप्त हो जाते हैं, तो सभी ऑब्जेक्ट्स को हटाने के लिए इसे बंद करें और मेमोरी को सिस्टम में वापस करें:

ei_reg_close(reg);    

Mnesia को रजिस्ट्री का बैकअप लेना

एक रजिस्ट्री की सामग्री को "पास के" Mnesia नोड पर Mnesia तक Mnesia किया जा सकता है। आपको Erlang नोड को एक खुला कनेक्शन प्रदान करना होगा ( erl_connect देखें)। इसके अलावा, Mnesia 3.0 या बाद में बैकअप शुरू होने से पहले Erlang नोड पर चलना चाहिए:

ei_reg_dump(fd, reg, "mtab", dumpflags);      

यह उदाहरण रजिस्ट्री की सामग्री को निर्दिष्ट Mnesia तालिका "mtab" । एक बार एक रजिस्ट्री इस तरह से Mnesia लिए बैकअप लिया गया है, अधिक बैकअप केवल उन वस्तुओं को प्रभावित करते हैं जिन्हें सबसे हाल ही में बैकअप के बाद संशोधित किया गया है, अर्थात, जो ऑब्जेक्ट बनाए गए हैं, बदल गए हैं, या हटाए गए हैं। बैकअप ऑपरेशन को एकल परमाणु लेनदेन के रूप में किया जाता है, ताकि या तो संपूर्ण बैकअप प्रदर्शन हो या इसमें से कोई भी नहीं।

इसी तरह, एक Mnesia तालिका से एक रजिस्ट्री को बहाल किया जा सकता है:

ei_reg_restore(fd, reg, "mtab");      

यह "mtab" की संपूर्ण सामग्री को निर्दिष्ट रजिस्ट्री में पढ़ता है। पुनर्स्थापना के बाद, रजिस्ट्री में सभी वस्तुओं को अनमॉडिफाइड के रूप में चिह्नित किया जाता है, इसलिए बाद में बैकअप केवल उन वस्तुओं को प्रभावित करता है जिन्हें आपने पुनर्स्थापना के बाद संशोधित किया है।

ध्यान दें कि यदि आप एक गैर-रिक्त रजिस्ट्री में पुनर्स्थापित करते हैं, तो तालिका में ऑब्जेक्ट उसी कुंजियों के साथ रजिस्ट्री में ऑब्जेक्ट को अधिलेखित करते हैं। इसके अलावा, रजिस्ट्री की पूरी सामग्री को पुनर्स्थापित करने के बाद अनमॉडिफाइड के रूप में चिह्नित किया जाता है, जिसमें कोई भी संशोधित ऑब्जेक्ट शामिल नहीं है जो पुनर्स्थापना कार्रवाई द्वारा ओवरराइट नहीं किया गया था। यह आपका इरादा नहीं हो सकता है।

भंडारण स्ट्रिंग्स और बायनेरिज़

जब स्ट्रिंग या बाइनरी ऑब्जेक्ट्स को रजिस्ट्री में संग्रहीत किया जाता है तो यह महत्वपूर्ण है कि कुछ सरल दिशानिर्देशों का पालन किया जाए।

सबसे महत्वपूर्ण बात, ऑब्जेक्ट को malloc() या (समान) के लिए एक कॉल के साथ बनाया गया होगा, ताकि बाद में इसे एकल कॉल द्वारा free() । जब इसे बंद किया जाता है, या जब आप पहले किसी स्ट्रिंग या बाइनरी में किसी ऑब्जेक्ट को नया मान असाइन करते हैं, तो रजिस्ट्री द्वारा ऑब्जेक्ट्स को मुक्त कर दिया जाता है।

ध्यान दें कि यदि आप बाइनरी ऑब्जेक्ट्स को संदर्भित करते हैं जो संदर्भ-निर्भर हैं (उदाहरण के लिए, जिसमें पॉइंटर्स या ओपन फाइल डिस्क्रिप्टर हैं), तो वे अपना अर्थ खो देते हैं यदि वे Mnesia टेबल पर बैकअप लिए Mnesia हैं और बाद में एक अलग संदर्भ में बहाल होते हैं।

जब आप रजिस्ट्री से एक संग्रहीत स्ट्रिंग या बाइनरी मान प्राप्त करते हैं, तो रजिस्ट्री ऑब्जेक्ट के लिए एक पॉइंटर रखता है और आपको उस पॉइंटर की एक प्रति प्रदान की जाती है। आपको इस तरह से पुनर्प्राप्त की गई वस्तु को कभी भी मुक्त नहीं करना चाहिए क्योंकि जब रजिस्ट्री बाद में इसे मुक्त करने का प्रयास करती है, तो एक रनटाइम त्रुटि होती है जो संभावित रूप से सी-नोड क्रैश होने का कारण बनती है।

आप इस तरह से पुनः प्राप्त किसी वस्तु की सामग्री को संशोधित करने के लिए स्वतंत्र हैं। हालाँकि, जब आप ऐसा करते हैं, तो रजिस्ट्री को आपके परिवर्तनों के बारे में पता नहीं होता है, संभवतः इससे अगली बार जब आप रजिस्ट्री सामग्री का Mnesia बैकअप बनाते हैं तो यह Mnesia । इससे बचा जा सकता है यदि आप registry:ei_reg_markdirty साथ ऐसे किसी भी परिवर्तन के बाद ऑब्जेक्ट को गंदे के रूप में चिह्नित करते हैं registry:ei_reg_markdirty , या registry:ei_reg_dump को उपयुक्त झंडे पास करें registry:ei_reg_dump