Пошаговое руководство по интеграции C в ваш проект Erlang.

Образовательных материалов о узлах C немного, и они устарели. Итак, я думаю, что эта история облегчит вашу интеграцию. Erlang — это не язык, созданный для манипулирования двух- или более многомерными массивами. С другой стороны, иногда вам нужно эффективно работать с двумерными или более массивами. Можно выполнять манипуляции с двумерными массивами, используя тип данных Map, но это недостаточно эффективно. Вместо этого использование узлов C для манипулирования двумерными массивами намного эффективнее и в нашем проекте было в 7 раз быстрее. Итак, если вам нужна эффективность, вы должны использовать C. К счастью, интеграция с помощью C Nodes очень проста.

Узлы Эрланга

С другой стороны, чтобы понять узлы C, нам нужно понять узлы Erlang. Узлы Erlang — это системы времени выполнения. Когда вы вызываете erl в терминале, вы создаете узел Erlang. Узлы Erlang могут взаимодействовать через конструкторы отправки и получения. Таким образом, вы можете общаться между узлами, используя pid, как два процесса, взаимодействующие в одном узле. Но если вы хотите использовать зарегистрированные имена, вы должны указать узел рядом с зарегистрированным именем процесса, потому что зарегистрированные имена являются локальными для каждого узла. Вы можете назвать свои узлы флагами -name или -sname (обозначает короткое имя) после команды erl на терминале.

Имя узла с именем хоста можно увидеть в оболочке erlang в начале каждой строки и показать при вводе node(). Узлы, созданные с коротким именем, не могут взаимодействовать с узлами, созданными с длинным именем. Вы можете легко увидеть открытые и подключенные узлы, набрав nodes() . Соединение может быть установлено с помощью net_adm:ping(‹Node@Hostname›) или путем отправки сообщения этому узлу. Функция net_adm:ping вернет pong, если соединение будет успешно установлено, и вернет pang, если соединение не удастся.

С другой стороны, вы можете напрямую отправить сообщение на узел Erlang через зарегистрированное имя и имя узла вместе, и соединение будет установлено автоматически.

C-узлы

Мы можем перейти к узлам C, потому что мы рассмотрели узлы Erlang на базовом уровне. Узел C устанавливается с использованием библиотеки интерфейса Erlang в c. Во-первых, вы должны инициализировать интерфейс Erlang.

ei_init();

Затем вы можете инициализировать свой узел c. Если вы используете короткие имена в качестве имен узлов, вы должны назвать свои c-узлы c‹n›@hostname (c1@yusufpro), где n — номер вашего c-узла. При использовании длинных имен такого ограничения нет. (http://erlang.org/documentation/doc-5.5.1/doc/tutorial/cnode.html)

ei_connect_init автоматически добавляет имя хоста в конце. Вы можете проверить созданное вами имя узла с помощью функции ei_thishostname.

const char *nodename = ei_thishostname(&ec);

Я действительно боролся здесь с первой попытки, потому что имя хоста моего узла C не имело заглавных букв. Но в части имени хоста моего узла Erlang действительно были заглавные буквы. Если у вас возникла эта проблема, вам нужно изменить свое имя хоста с помощью scutil — установите HostName ‹new hostname› в вашей оболочке bash.

После инициализации узла C вы можете использовать два типа подхода к подключению. Первый использует узел C в качестве клиента и узел Erlang в качестве сервера. В этом случае узел Erlang должен находиться в режиме ожидания, пока вы пытаетесь подключиться с узла C.

char *erlang_node_name = "node1@yusufpro";
int fd = ei_connect(&ec, erlang_node_name);

Значение fd (файловый дескриптор), возвращаемое функцией ei_connect, зарезервировано для использования при получении и отправке сообщений. Если значение fd является отрицательным целым числом, это означает, что попытка подключения не удалась.

Второй подход заключается в использовании узла Erlang в качестве клиента и узла C в качестве сервера. В этом подходе вы должны настроить сокет для прослушивания, опубликовать его и принять входящее соединение.

Функция ei_accept также возвращает fd. Если какое-либо из возвращаемых значений этих функций меньше 0, это означает, что эти функции не выполнились. Поэтому вы должны понять и исправить ошибку, прежде чем двигаться дальше.

Для приема или отправки данных используется тип данных ei_x_buff. Для получения дополнительной информации о типе данных ei_x_buff: http://erlang.org/doc/man/ei.html#data-types. Этот тип данных состоит из двух полей. Первый — это buff, представляющий собой массив символов, который содержит данные в формате внешнего термина. Для получения дополнительной информации о формате внешнего термина посетите https://erlang.org/doc/apps/erts/erl_ext_dist.html. Второй — индекс, который представляет собой целое число, содержащее длину баффа, на которую указывает указатель баффа.

ei_x_buff &buff_object;
ei_x_new_with_version(&buff_object);

После создания бафф-объекта его можно наполнить функциями кодирования в Erlang Interface Library (http://erlang.org/doc/man/ei.html#ei_encode_atom). Функции кодирования возвращают отрицательное целое число, если не могут выполнить действие должным образом. В следующем примере мы заполняем объект buff с помощью

#{first=›[1,3], second=›{1,2}} этой карты.

Чтобы отправить это сообщение зарегистрированному процессу «worker» узла Erlang, мы собираемся использовать функцию ei_reg_send.

ei_reg_send(&ec, fd, <process_name> , buff_object.buff, buff_object.index);

Здесь ec — это инициализированный узел c, fd — файловый дескриптор, который вы получили ранее из функций подключения, ‹process_name › — атом зарегистрированного имени процесса, buff — это сообщение, а index — это длина сообщения.

Как видите, Erlang автоматически декодирует внешний терм.

Обычно для отправки сообщения должны быть указаны имя процесса и имя узла. Однако, поскольку обычный узел C не имеет более одного процесса, в отличие от узла Erlang, вы можете указать любой атом вместо имени процесса.

(node1@YusufPro)1> {any,c1@YusufPro} ! #{first => [1,-1],second => {1,2}}.

Чтобы получить сообщение от узла Erlang, нам нужен объект erlang_msg, который содержит информацию о сообщении, такую ​​как передаваемые pids или cookie, описание файла, которое мы получили от соединения, и объект ei_x_buff, который мы создали для хранения данных.

erlang_msg msg;
ei_xreceive_msg(fd, &msg, &buff_object);

ei_xreceive_msg вернет отрицательное целое число в случае сбоя. В противном случае он заполнит buff_object внутри.

Чтобы декодировать внешний термин в C, нам нужен индекс декодирования, который содержит то место, где мы находимся при декодировании. Функции декодирования изменяют индекс декодирования на конец декодированных данных. Чтобы декодировать объект buff_object, который содержит

#{first=›[1,-1], second=›{1,2}} формат внешнего термина этой карты, нам нужно соответственно декодировать все данные в терме.

После того, как мы запустим код и отправим карту на узел C непосредственно из узла Erlang, мы сможем декодировать. Затем, чтобы увидеть это ясно, мы можем распечатать значения, полученные в процессе декодирования.

Вывод

Erlang очень хорош для изучения чисто функционального программирования. Однако очень сложные манипуляции с массивами могут иметь большое значение. Узлы C преодолевают это препятствие и делают язык лучше.

Я надеюсь, что это руководство поможет вам интегрировать C в вашу программу Erlang.

Не стесняйтесь обращаться ко мне, если вы думаете, что я что-то пропустил или сделал ошибку. Спасибо за уделенное время.