Изучение связи портов в Erlang: подробное руководство

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

Метод 1: использование драйвера порта
Erlang предоставляет интерфейс драйвера порта, который позволяет вам писать собственные драйверы на C или C++ для взаимодействия с внешними программами. Вот пример простого драйвера порта на C:

#include "erl_driver.h"
static ErlDrvData start(ErlDrvPort port, char* cmd)
{
    // Initialization code
    return NULL;
}
static void stop(ErlDrvData data)
{
    // Cleanup code
}
static void process(ErlDrvData data, ErlIOVec* ev)
{
    // Handle incoming messages from Erlang
}
ErlDrvEntry port_driver_entry = {
    NULL,        /* F_PTR init, called when driver is loaded */
    start,       /* L_PTR start, called when port is opened */
    stop,        /* F_PTR stop, called when port is closed */
    NULL,        /* F_PTR output, called when Erlang has sent */
    NULL,        /* F_PTR ready_input, called when input descriptor ready */
    NULL,        /* F_PTR ready_output, called when output descriptor ready */
    "my_port_drv", /* char *driver_name, the argument to open_port */
    NULL,        /* F_PTR finish, called when unloaded */
    NULL,        /* void *handle, Reserved by VM */
    process,     /* F_PTR control, port_command callback */
    NULL,        /* F_PTR timeout, reserved */
    NULL,        /* F_PTR outputv, reserved */
    NULL,        /* F_PTR ready_async, only for async drivers */
    NULL,        /* F_PTR flush, called when port is about
                    to be closed, but there is data in driver
                    queue */
    NULL,        /* F_PTR call, much like control, sync call
                    to driver */
    NULL,        /* F_PTR event, called when an event selected
                    by driver_event() occurs. */
    ERL_DRV_EXTENDED_MARKER,
    ERL_DRV_EXTENDED_MAJOR_VERSION,
    ERL_DRV_EXTENDED_MINOR_VERSION,
    ERL_DRV_FLAG_USE_PORT_LOCKING,
    NULL,        /* Reserved */
    NULL,        /* F_PTR process_exit, called when a process
                    monitored by a driver dies */
};
DRIVER_INIT(my_port_drv)
{
    return &port_driver_entry;
}

Метод 2: использование функции open_port
Erlang предоставляет функцию open_port, которая позволяет выполнять внешние программы и взаимодействовать с ними посредством стандартного ввода и вывода. Вот пример:

{ok, Port} = open_port({spawn, "my_program"}, [stream]),
Port ! {self(), {command, "Hello"}},
receive
    {Port, {data, Data}} -> io:format("Received: ~p~n", [Data])
end,
Port ! {self(), close}.

Метод 3: использование модуля erl_interface
Модуль erl_interfaceпредоставляет функции для связи с узлами Erlang с использованием внешнего формата терминов Erlang (ETF). Вы можете использовать этот модуль для установления связи между Erlang и внешними программами. Вот пример:

{ok, Port} = erl_interface:connect("localhost", 1234),
erl_interface:send(Port, {self(), {command, "Hello"}}),
receive
    {Port, {data, Data}} -> io:format("Received: ~p~n", [Data])
end,
erl_interface:close(Port).

В этой статье мы рассмотрели различные методы связи портов в Erlang. Мы рассмотрели использование драйверов портов, функции open_portи модуля erl_interface. Каждый метод обеспечивает разные уровни гибкости и контроля над процессом связи. Используя эти методы, вы можете легко интегрировать Erlang с внешними программами и построить надежные распределенные системы.