Порт
Функции для взаимодействия с внешним миром через порты.
Порты предоставляют механизм для запуска процессов операционной системы, внешних по отношению к Erlang VM, и взаимодействия с ними посредством обмена сообщениями.
Пример
END_OF_DOCUMENT_MARKERВ приведённом примере мы создали новый порт, выполняющий программу cat. cat — это программа, доступная в системах UNIX, которая получает данные с нескольких входов и конкатенирует их на выходе.
После создания порта мы отправили ему два команды в виде сообщений, используя Kernel.send/2. Первая команда содержит двоичную нагрузку «hello», а вторая — «world».
После отправки этих двух сообщений, мы вызвали помощника IEx flush(), который напечатал все полученные от порта сообщения, в данном случае «hello» и «world». Обратите внимание, что сообщения находятся в двоичном формате, поскольку мы передали :binary опцию при открытии порта в Port.open/2. Без такой опции, на выходе получился бы список байтов.
После завершения всех операций, мы закрыли порт.
Elixir предоставляет множество удобств для работы с портами, а также некоторые недостатки. Мы рассмотрим их ниже.
API сообщений и функций
Для работы с портами существуют два API. Это может быть либо асинхронный обмен сообщениями, как в примере выше, либо вызов функций данного модуля.
Ниже перечислены поддерживаемые портами сообщения и соответствующие им функции API:
-
{pid, {:command, binary}}— отправляет заданные данные в порт. См.command/3. -
{pid, :close}— закрывает порт. Если порт ещё не закрыт, порт ответит сообщением{port, :closed}после очистки своих буферов и фактического закрытия. См.close/1. -
{pid, {:connect, new_pid}}— устанавливаетnew_pidв качестве нового владельца порта. После открытия порта, порт связан и подключен к вызывающему процессу, и взаимодействие с портом происходит только через подключенный процесс. Это сообщение делаетnew_pidновым подключённым процессом. Если порт не завершён, порт ответит старому владельцу сообщением{port, :connected}. См.connect/2.
В свою очередь, порт отправит подключённому процессу следующие сообщения:
-
{port, {:data, data}}— данные, отправленные портом -
{port, :closed}— ответ на сообщение{pid, :close} -
{port, :connected}— ответ на сообщение{pid, {:connect, new_pid}} -
{:EXIT, port, reason}— сигналы завершения в случае сбоя порта. Если reason не:normal, это сообщение будет получено только если владелец процесса обрабатывает завершения
Механизмы открытия
Порт можно открыть четырьмя основными способами.
В качестве краткого резюме, предпочтительнее использовать опции :spawn и :spawn_executable, упомянутые ниже. Остальные две опции, :spawn_driver и :fd, предназначены для расширенного использования внутри VM. Также рассмотрите использование System.cmd/3, если всё, что вам нужно, это запуск программы и получение её возвращаемого значения.
spawn
Кортеж :spawn получает двоичные данные, которые будут исполнены как полное вызов. Например, мы можем использовать его для прямого вызова «echo hello»:
:spawn извлечёт имя программы из аргумента и переберётся по переменной окружения $PATH вашего ОС в поисках соответствующей программы.
Хотя это удобно, это означает, что невозможно вызвать исполняемый файл, имя которого или любого из его аргументов содержит пробелы. По этим причинам, большинство случаев предпочтительнее использовать :spawn_executable.
spawn_executable
Spawn executable — это более ограниченная и явная версия spawn. Она ожидает полные пути к исполняемому файлу, который вы хотите запустить. Если они находятся в вашей $PATH, их можно получить, вызвав System.find_executable/1:
При использовании :spawn_executable, список аргументов можно передать через опцию :args, как показано выше. Полный список опций см. в документации функции Erlang :erlang.open_port/2.
spawn_driver
Spawn driver используется для запуска драйверов портов, которые представляют собой программы, написанные на C, реализующие определённые протоколы связи и динамически связанные с Erlang VM. Драйверы портов — это продвинутая тема и один из механизмов интеграции кода C наряду с NIF. Для получения дополнительной информации, пожалуйста, обратитесь к документации Erlang по ссылке.
fd
Опция имени :fd позволяет разработчикам получить доступ к in и out дескрипторов файлов, используемых Erlang VM. Вы будете использовать их только в том случае, если вы переписываете основную часть системы выполнения, например, процессы :user и :shell.
Процессы-зомби
Порт может быть закрыт с помощью функции close/1 или отправкой сообщения {pid, :close}. Однако, если VM аварийно завершит работу, долго выполняемая программа, запущенная портом, будет иметь закрытыми каналы stdin и stdout, но не будет автоматически завершена.
Хотя большинство инструментов командной строки UNIX завершат работу, как только их каналы связи будут закрыты, не все приложения командной строки будут делать так. Хотя мы рекомендуем плавное завершение, определяя, был ли stdin/stdout закрыт, у нас не всегда есть контроль над тем, как 3-х стороннее ПО завершает работу. В таких случаях, вы можете обернуть приложение в скрипт, который проверяет stdin. Вот такой скрипт на bash:
END_OF_DOCUMENT_MARKERТеперь вместо:
END_OF_DOCUMENT_MARKERВы можете вызвать:
END_OF_DOCUMENT_MARKERРезюме
Типы
- name()
Функции
- close(port)
-
Закрывает
port - command(port, data, options \\ [])
-
Отправляет
dataв драйвер портаport - connect(port, pid)
-
Связывает идентификатор
portсpid - info(port)
-
Возвращает информацию о
portилиnilесли порт закрыт - info(port, spec)
-
Возвращает информацию о
portилиnilесли порт закрыт - list()
-
Возвращает список всех портов в текущем узле
- open(name, settings)
-
Открывает порт, используя кортеж
nameи списокoptions
Типы
name()
END_OF_DOCUMENT_MARKERФункции
close(port)
END_OF_DOCUMENT_MARKERЗакрывает port.
Для получения дополнительной информации, см. :erlang.port_close/1.
Вставлено компилятором.
command(port, data, options \\ [])
END_OF_DOCUMENT_MARKERОтправляет data в драйвер порта port.
Для получения дополнительной информации, см. :erlang.port_command/2.
Вставлено компилятором.
connect(port, pid)
END_OF_DOCUMENT_MARKERСвязывает идентификатор port с pid.
Для получения дополнительной информации, см. :erlang.port_connect/2.
Вставлено компилятором.
info(port)
Возвращает информацию о port или nil если порт закрыт.
Для получения дополнительной информации, см. :erlang.port_info/1.
info(port, spec)
END_OF_DOCUMENT_MARKERВозвращает информацию о port или nil если порт закрыт.
Для получения дополнительной информации, см. :erlang.port_info/2.
list()
END_OF_DOCUMENT_MARKERВозвращает список всех портов в текущем узле.
Вставлено компилятором.
open(name, settings)
END_OF_DOCUMENT_MARKERОткрывает порт, используя кортеж name и список options.
В документации модуля выше содержатся документация и примеры поддерживаемых name значений, которые подведены в таблице ниже:
-
{:spawn, command}— запускает внешнюю программу.commandдолжен содержать имя программы и, необязательно, список аргументов, разделённых пробелами. Если передаются программы или аргументы с пробелами в их имени, используйте следующую опцию. -
{:spawn_executable, filename}— запускает исполняемый файл, указанный абсолютным путёмfilename. Аргументы могут быть переданы через опцию:args. -
{:spawn_driver, command}— запускает так называемые драйверы портов. -
{:fd, fd_in, fd_out}— получает доступ к дескрипторам файлов,fd_inиfd_outоткрытых VM.
Для получения дополнительной информации и списка опций, см. :erlang.open_port/2.
Вставлено компилятором.
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.5.3/Port.html