はじめに
open_portの全仕様が書かれた日本語のドキュメントが見つからなかったため、自分で書くことにした。
(勉強も兼ねて。)
以下のドキュメントを素にしている。
公式ドキュメント(もちろん英語)
http://erlang.org/doc/man/erlang.html#open_port-2
Spec
spec.hrl
-spec open_port(PortName, PortSettings) -> port() when
PortName :: {spawn, Command :: string() | binary()}
| {spawn_driver, Command :: string() | binary()}
| {spawn_executable, FileName :: file:name()}
| {fd, In :: integer() >= 0, Out :: integer() >= 0},
PortSettings :: [Opt],
Opt :: {packet, N :: 1 | 2 | 4}
| stream
| {line, L :: integer() >= 0}
| {cd, Dir :: string() | binary()}
| {env, Env :: [{Name :: string(), Val :: string() | false}]}
| {args, [string() | binary()]}
| {arg0, string() | binary()}
| exit_status
| use_stdio
| nouse_stdio
| stderr_to_stdout
| in
| out
| binary
| eof
| {parallelism, Boolean :: boolean()}
| hide.
仕様
- 新しいErlangポートを開いてポート識別子を返す
- ポートは外部Erlangプロセスとして扱える
- システムがUnicodeファイル名モードで実行されている場合、以下のものはすべてUnicodeファイル名変換の対象
- 実行可能ファイル名
-
cd
、env
、args
、arg0
の引数
- 変換を避ける、または、UTF-8に強制するためには
- 正しいエンコーディングバイナリとして実行ファイルと引数を与える
- 詳細は、 fileモジュール 、
file:native_name_encoding/0
、stdlib
ユーザーズガイドを参照
注意
- ErlangのVMをUnicodeファイル名変換モードで起動した場合
- 名前(Listの場合)の文字 > 255 のみ
- そうでない場合
- 実行可能ファイル名はISO-Latin-1文字セットに制限される
PortName
{spawn, Command}
-
外部プログラムを起動
-
Command
- 起動する外部プログラムの名前
- 同名のErlangドライバが存在しない
- Erlangのワークスペース外で
Command
を実行する
- Erlangのワークスペース外で
- 同名のErlangドライバが存在する
- そのドライバを起動
- Erlangのワークスペース内で実行される
= Erlangランタイムシステムにリンクされる
- スペースで区切った最初のトークン
= 実行可能ファイル(or ドライバ)の名前- ファイルまたはディレクトリ名にスペースを持つプログラムの実行に適さない
→ 代わりに{spawn_executable, Command}
を使う
- ファイルまたはディレクトリ名にスペースを持つプログラムの実行に適さない
-
-
Solaris の場合
- システムコールvforkが使われる
- パフォーマンス上の理由でforkより優先される
- 信頼性は低い
- vforkを使うことに問題がある場合
- 環境変数
ERL_NO_VFORK
に任意の値をセット
→ forkを代わりに使うことができる
- 環境変数
- システムコールvforkが使われる
- 実行時、
PATH
を使う- OSによってはプログラムを見つけるために環境メソッドを使う
- 特定プラットフォーム上でシェルを起動することによって決まる
{spawn_driver, Command}
-
{spawn, Command}
のように動作-
Command
のスペース区切りトークンの最初
→ ロードされたドライバの名前でないといけない- その名前のドライバがロードされていない場合
- エラー
badarg
が発生
- エラー
- その名前のドライバがロードされていない場合
-
{spawn_executable, FileName}
-
{spawn, FileName}
のように動作- 外部実行可能ファイルの実行しかできない
-
FileName
- 全体で実行可能ファイルの名前
- スペースを含む
- 引数を渡す場合
-
PortSettings
のargs
とarg0
を使う
-
- 全体で実行可能ファイルの名前
- シェルは直接実行される
- 通常プログラムを起動するために呼び出されていない
-
PATH
等は検索されない- 実行するプログラムの
PATH
を検索するにはos:find_executable/1
を使う
- 実行するプログラムの
- シェルスクリプトまたは .batファイルが実行された場合だけ
→ 適切なコマンドインタプリタが暗黙的に呼び出される- しかし、まだコマンドの引数の拡張、暗黙的な
PATH
の検索はされない
- しかし、まだコマンドの引数の拡張、暗黙的な
-
FileName
が実行できない場合- POSIXのエラーコードとエラー例外が発生
- エラーの理由はOS間で異なる可能性あり
- 発生するエラー
-
enoent
- 見つからないプログラムが実行されようとしたとき
-
eaccess
- 与えられたファイルが実行可能でないとき
-
- POSIXのエラーコードとエラー例外が発生
{fd, In, Out}
- Erlangプロセスはファイルディスクリプタにアクセスすることができる
- 対象のファイルディスクリプタ
- 現在開いている
- Erlangによって使用されている
-
In
- 標準入力として使用することができる
-
Out
- 標準出力として使用することができる
- Erlang OS(shell, user)の様々なサーバでのみ利用される
→ 仕様は非常に限られる
- 対象のファイルディスクリプタ
PortSettings
{packet, N}
- メッセージの先頭に長さが
N
バイト長で送られる-
N
- 1, 2, 4のどれかのみ
-
stream
- 出力メッセージをパケット長なしで送信
- ユーザ定義のプロトコルを使用しなければならない
- Erlangプロセス - 外部オブジェクト間
{line, L}
- メッセージが行ごとに配信される
- それぞれの行は1つのメッセージで配信
- 行: OS依存の改行文字で区切られている
- それぞれの行は1つのメッセージで配信
- メッセージのデータ形式は
{Flag, Line}
-
Flag
-
eol
またはnoeol
-
-
Line
- 配信された実際のデータ
- 改行文字を持たない
- 配信された実際のデータ
-
-
L
- 最大の行の長さ
- バイト単位
- これよりも長い行は、複数のメッセージで送られる
-
Flag
にnoeol
が設定されている - 最後のメッセージは
eol
- EOFが来たり、すぐに新しいシーケンスが続かなかったりした場合、
noeol
- EOFが来たり、すぐに新しいシーケンスが続かなかったりした場合、
-
- 最大の行の長さ
-
{packet, N}
と{line, L}
は相互排他
{cd, Dir}
-
{spawn, Command}
と{spawn_executable, FileName}
にのみ有効 - 外部プログラムの作業ディレクトリが
Dir
になる-
Dir
はstring()
-
{env, Env}
-
{spawn, Command}
と{spawn_executable, FileName}
にのみ有効 - 環境仕様に
Env
を追加-
Env
は{Name, Val}
のリスト-
Name
は 環境変数名string()
-
Val
は 生成されたポートプロセスで持つ値string()
- 例外として
false
が使える- 環境変数を除去
-
os:getenv/1
と同じ
-
-
{args, [string() | binary()]}
-
{spawn_executable, FileName}
に有効 - 実行可能ファイルに引数を指定
- 各引数は別々の文字列として与えられる
- Unix上
- 引数ベクトルにおける一つの要素
- 他のプラットフォーム
- 似たような挙動
- 引数はシェルによって展開されない
- 特に注意すべきことは ワイルドカードが展開されないこと
- ワイルドカードを展開するには
filelib:wildcard/1
を使う - これはUnixシェルスクリプトでも同じ
- ワイルドカードが展開されずに実行される
- Windows®では、ワイルドカード展開はプログラム自身で行っているので問題にならない
- ワイルドカードを展開するには
- 特に注意すべきことは ワイルドカードが展開されないこと
- 実際に実行するファイル名(
argv[0]
)はこのリストで指定しない- 適切な実行可能ファイル名が
argv[0]
として使われる - 何らかの理由で引数ベクトルにプログラム名を明示的に設定したい場合は
argv[0]
を使う
- 適切な実行可能ファイル名が
{arg0, string() | binary()}
-
{spawn_executable, FileName}
でのみ有効- 実行可能ファイルを実行するときにプログラム名引数を明示的に指定
- 一部のOSの特定の状況下では望ましい時がある
- プログラムの返答の仕方はかなりシステムに依存
- 具体的な影響は保証されない
exit_status
-
{spawn, Command}
と{spawn_executable, FileName}
で有効-
Command
は 外部プログラム のみ
-
- 外部プロセス終了時、
{Port, {exit_status, Status}}
が送られる-
Status
は外部プロセスの終了ステータス- Unix上で以上終了した時はシェルと同じ規則
- 128+signal
- Unix上で以上終了した時はシェルと同じ規則
-
-
eof
オプションが指定されている場合-
eof
メッセージとexit_status
メッセージの順序は決まっていない
-
- ポートプログラムが終了せず、標準出力を閉じた場合は、
exit_status
は機能しない
use_stdio
-
{spawn, Command}
と{spawn_executable, FileName}
で有効- (UNIX)プロセスの標準出入出力が使用可能になる
- ファイルディスクリプタ0、1
- (UNIX)プロセスの標準出入出力が使用可能になる
nouse_stdio
-
use_stdio
の逆- Erlangとの通信にファイルディスクリプタ3, 4を使用
stderr_to_stdout
- 外部プログラムへのポートに影響
- 標準エラー出力を標準出力に出す
-
stderr_to_stdout
とnouse_stdio
は相互排他
overlapped_io
- 外部プログラムへのポートに影響
- Windows® でのみ
- ポートプログラムが標準入力と標準出力ハンドル上でオーバーラップされたI/Oを扱う
- 標準ハンドルが
FILE_FLAG_OVERLAPPED
と一緒に開かれる
- 標準ハンドルが
- 単純なポートプログラム用で経験の豊富なWindowsプログラマのためのオプションではない
- 他のプラットフォームでは無視される
in
- 入力のためだけにポートが使える
out
- 出力のためだけにポートが使える
binary
- ポートからのすべてのI/Oが
binary()
になる
eof
- portを開いたまま、
{Port, eof}
メッセージをポートを保持しているプロセスに送信する
hide
- ポートプログラムを起動するときに、新しいコンソールウィンドウを作らない
- Windows上で実行している場合
- 他のプラットフォームには影響を与えない
{parallelism, Boolean}
- ポートの並列処理のためにスケジューラヒントを設定
-
true
- システム内の並列性を向上させようとする
- VMはシステム内で並列処理を改善するためにポートタスクをスケジューリングする
-
false
- VMは並列性を犠牲にしてレイテンシを改善
- すぐにポートのタスクを実行しようとする
-
- デフォルトはerl起動時にコマンドライン引数+sppで設定
- 対象
- ポートのすべての型のためのstream
- 生成されたポートのための
use_stdio
エラー
- ポートがオープンできない場合
badarg
-
- Posixのエラーコード
- もっとも詳細にエラーを説明
- 対応するPosixコードがない場合は
einval
badarg
-
open_port
の引数の問題
system_limit
- Erlangエミュレータで利用できるポートがない
enomem
- 十分なメモリがない
- ポートを生成するための
eagain
- 利用可能なOSのプロセスがない
enametoolong
- 与えられた外部コマンドが長過ぎる
emfile
- 利用可能なファイルディスクリプタがない
- Erlangエミュレータが走るOSプロセスのための
enfile
- ファイルテーブルがいっぱい
- 全OS
eacces
-
{spawn_executable, Command}
で与えられたCommand
が実行可能ファイルでない
enoent
-
{spawn_executable, FileName}
で与えられたFileName
が存在しない
{'EXIT', Port, PosixCode}
- ポート使用時のエラー
- ポートを使用しているプロセスに伝えられる
- 対象
-
{spawn, Name}
、{spawn_driver, Name}
または{spawn_executable, Name}
-
-
PosixCode
の取り得る値については file (?) を参照 - 同時に開くことができるポートの最大数
外部サイト
公式ドキュメント(もちろん英語)
http://erlang.org/doc/man/erlang.html#open_port-2
いろはメモ - Erlang 編 - 「は」 : ポートによる外部接続 - lnzntの Erlang 日記 - はてなグループ: erlang
http://erlang.g.hatena.ne.jp/lnznt/20110814/1313283961
書籍
-
「プログラミングErlang」 には
- 基本的な使い方の記述あり
- 良く使われる
PortName
とOpt
だけ紹介
- 「すごいErlangゆかいに学ぼう」 は…