IPC command: idle. ret: {}
IPC command: hello. ret: {"reply"=>"hello"}
IPC command: upper with param {"A"=>"dog", "B"=>"Cat"} ret: {"A"=>"DOG", "B"=>"CAT"}
===== 解説 =====
サーバーは、AlWorkerを継承したクラスに "ipc_" をプレフィックスとして付与したメソッドを定義すると、AloneにはIPCコマンドのイベントハンドラとして認識されます。\\
クライアントは、AlWorker::IPC.openメソッドでサーバーに接続し、call メソッドで IPCコールを行います。
サーバー/クライアント間のパラメータ送受は、Hashを使います。\\
各ハンドラでは、trueを返すとクライアントとのセッションを継続し、falseだとサーバー側から切断します。上記例ではreply()メソッドが必ずtrueを返すので、セッションが継続します。\\
====== CGIコントローラから使う ======
ウェブブラウザを使って状態監視等を行う場合には、クライアントプログラムがCGIプログラムになります。
{{:alworker:IPC_explain2.png?nolink|}}
===== サンプル =====
<%= footer_section %>
@ipc = Ipc.new( "/PATH/TO/socketfile" )
@ipc.chmod = 0666
@ipc.run( self )
====== 同期/非同期 ======
イベントハンドラはデフォルトで同期的に呼び出され、たとえば2つのクライアントから同時にコマンドを受信しても、一つずつ実行します。\\
非同期にしたい場合は、"ipc_a_" をプレフィックスとして付けます。\\
def ipc_a_idle( sock, param )
reply( sock, 200, "OK" )
end
====== IPCのエラー ======
httpステータスコードに倣った、IPCステータスコードを採用しています。\\
IPCコマンドメソッドでエラーを検出し、それをクライアントへ返したい場合、reply()メソッドの引数で指示します。\\
ステータスコード(数字)と、ステータス文字列は、httpステータスコードに近い状態がある場合はそれを使うように努力してください。\\
クライアント側では、ipcオブジェクトのstatus_codeアトリビュートを使って参照します。
ipc.call( "idle" )
puts ipc.status_code
ipc.call( "noexist" )
puts ipc.status_code
===== 実行結果 =====
200 OK
501 Error Command not implemented.
====== 標準で用意してあるIPCコマンド ======
クライアント(IpcClient)に用意してあるメソッド
^メソッド^動作^返り値^
|call|任意のIPCコマンドを呼び出す|Hash|
|call_json|任意のIPCコマンドを呼び出す|JsonString|
|set_value|@valuesのセッター| |
|get_value|@valuesのゲッター|Object or Hash|
|get_value_wt|@valuesのゲッター タイムアウト付き|Object or Hash|
サーバー側
^IPCコマンド^動作^同期^タイムアウト^備考^
|quit|終了|async|--| |
|get_values|値取得 全データ|async|しない| |
|get_values "key1"|値取得 指定データ|async|しない|標準プロトコルではないが、利便性のために用意してある|
|get_values {"key":["key1"...]}|値取得 指定データ|async|しない| |
|get_values_wt|値取得 全データ|async|1s| |
|get_values_wt "key1"|値取得 指定データ|async|1s|標準プロトコルではないが、利便性のために用意してある|
|get_values_wt {"key":["key1"...],"timeout":5}|値取得 指定データ|async|指定| |
|set_values|値設定|async|しない| |
====== IPCプロトコル詳細 ======
IPCは、UNIX Socket + テキストベースで設計し、データ形式はJSONで統一してあります。これによって、対Rubyだけでなく、C言語など様々な言語からAlWorkerのIPCをコールすることができます。
リクエスト
command { parameter, encoded by json }
リプライ(ステータスのみの場合)
200 OK [any message if given.]
リプライ(データを含む場合)
200. OK [any message if given.]
{ data, encoded by json }
(LF)
リクエストは、コマンドに続いて、JSONエンコードしたパラメータを渡すことができます。\\
リプライは、httpプロトコルに倣ったステータス行を返し、必要に応じてJSONエンコードしたデータを返す事ができます。\\
データの有無は、ステータスコードの数字直後のピリオドの有無で判断します。
====== IPCパススルー ======
IPCプロトコルに準拠しない、自由なテキストデータの送受信も可能です。これを、IPCパススルーと呼んでいます。
コマンドごとに、以下のように実装します。
===== サーバサイド =====
def ipc_passthrough1( sock, param )
# sock.gets / sock.puts を使って送受信する。
while txt = sock.gets
sock.puts txt
break if txt == "END\n"
end
# コネクションを切る
return false
end
===== クライアント =====
require "al_worker_ipc"
AlWorker::Ipc.open("/tmp/ipc_server") {|ipc|
# ipcは、AlWorekr::IpcClient < UNIXSocket のインスタンス
ipc.puts("passthrough1")
5.times {
ipc.puts("hello world.")
p ipc.gets()
}
}
===== 解説 =====
クライアントは、IPCソケットに接続後、"passthrough1" コマンドを発行します。\\
フレームワークによって上記メソッドが呼び出され、以後 sock を使って自由フォーマットで送受信できます。\\
終了時は、falseを返すと、サーバー側からコネクションを切断します。trueを返すと、切断はされず、再びコマンド受付に戻ります。