elisp でのネットワークプログラム

elispはプログラミング言語として(勿論emacs環境上ではあるが)十分実用に耐え、 ちょっとしたアプリケーションなどはすぐ実現できる。筆者もこのページの日記書き用にelisp でアプリケーションを組んで定型文の入力などを行っていたが、どうせなら、ネットワークを介してサーバーにアップロード までできればより便利だと思った。elispならばelispのみの実装でこれは可能である。 例えば秀丸に付属のマクロ言語も相当な能力があるが、このような機能を実現するためには、外部にDLLを用意するなど マクロ外での補助的な機構が必要となる。この点、elispを用いるならば"emacs"さえあれば、当該elispプログラムを インストールするだけで、そのプログラムが動かすことができ非常に便利だ。

本文章は、日記エディタにネットワーク更新機能を付加した際に調べた、elispにおけるネットワーク の取扱いについて纏めておく。なにぶん素人なもので、間違いなど含まれていることもあると思われることを あらかじめ断っておく。


elisp におけるプロセス

Emacs Lispプログラムで、同一マシンや別のマシン上の他のプロセスに対して TCPネットワーク接続を開く場合、ネットワーク接続を、非同期サブプロセスとして扱う。 一般的なサブプロセスは、Emacs内部では『プロセス』と呼ばれるLispオブジェクトで 表現される。Lispプログラムはこのオブジェクトを用いてサブプロセスと通信したりそれ を制御する。一方、ネットワークでの通信相手のプロセスはEmacsプロセスの子プロセスでは ないため、データの送受信のみが可能で、キルしたりシグナルを送 ることはできないという大きな違いがある。

elisp によるTCPネットワーク接続

elisp を用いてTCPネットワーク接続を開くには`open-network-stream' 関数を用いる。引数は、 `NAME'、`BUFFER-OR-NAME'、`HOST'、`SERVICE'の4つである。

open-network-stream 関数

ネットワーク接続におけるプロセス情報

`process-status' 関数は、引数 `PROCESS-NAME' にプロセス、バッファ、 プロセス名(文字列)、バッファ名(文字列)のいずれかを与えることで、PROCESS-NAMEの状態をシンボルとして返す。 一般のサブプロセスで得られるシンボルは `run'、`stop'、`exit'、`signal'、`nil'であるが、 ネットワーク接続に対しては`open'か`closed'をつねに返し、一般のサブプロセスに対してはこれらの いずれの値もけっして返さない。この性質を利用して、プロセスが一般のサブプロセスかネットワーク接続かを区別するのに用いる こともできる。

process-status 関数

コーディングシステム

プロセスへの入力、プロセスからの出力に対するコーディングシステムは、変数 `coding-system-for-write'、`coding-system-for-read' が`nil'以外であればこれを用いられ、それ以外ではデフォルトの機構で決まるものが用いられる。また、 関数 `set-process-coding-system'を用いて、プロセスPROCESSからの出力および入力 に用いるコーディングシステムを指定することも出きる。

set-process-coding-system 関数

プロセスへの入力

ネットワーク接続を確立した後は、以下の関数を用いてEmacsから入力を送ることができる。 サブプロセスへの入力は、サブプロセスがそれを受け取るまえにコーディングシステム を用いて普通は符号化される。以下の関数における、引数 PROCESS-NAME は、プロセスかプロセス名であること

process-send-string 関数

この関数は、文字列STRINGの内容を標準入力としてプロセス PROCESS-NAME に送る。

process-send-region 関数

この関数は、STARTとENDで定義される領域内のテキストを標準入力としてプロセスPROCESS-NAMEへ送る。 STARTとENDのどちらかがカレントバッファ内の位置を表す整数でもマーカでもないと、エラーを通知する。 (どちらが大きな数であるかは重要ではない。)

process-send-eof 関数

この関数は、プロセスPROCESS-NAMEが入力で「ファイルの終りEOF」を見る ようにする。EOFはそれまでに送ったテキストのあとにある。

プロセスからの出力

サブプロセスが標準出力に書く出力を受け取る方法としては、以下の2通りがある。

プロセスにバッファもフィルタ関数もなければ、その出力は破棄される。

サブプロセスからの出力は、端末入力を読んでいるとき、`sit-for'や`sleep-for'等の 待機関数を実行中のとき、或いは`accept-process-output'を実行中のとき等、 Emacsが待機している時にだけ到着する。 これにより、並行プログラムで一般に悩まされるタイミングエラーの問題が減少する。 たとえば、安全にプロセスを作成してから、バッファかフィルタ関数を指定する。この処理の途中で、 待機を行うような基本関数を呼び出さなければ、出力は到着しない。

ファイルから読むテキストと同様に、サブプロセスの出力は、バッファやフィル タ関数が受け取るまえにコーディングシステムを用いて普通は復号化する。

プロセスバッファ

プロセスにフィルタ関数がなければ、その出力はプロセスに対応付けられたバッファ(プロセスバッファ) に挿入される。プロセスバッファはプロセスがキルされたことを判定することにも用いられる。

process-buffer 関数

この関数は、プロセスPROCESSに対応付けられているバッファを返す。

set-process-buffer 関数

この関数は、プロセスPROCESSにバッファBUFFERを対応付ける。

get-buffer-process 関数

この関数はBUFFER-OR-NAMEに対応付けられたプロセスを返す。バッファに 複数のプロセスが対応付けられている場合には、それらの1つを選ぶ。(現 状では、もっとも最近に作られたプロセスを選ぶ。)同じバッファに複数 のプロセスを対応付けることは一般にはよくない。

accept-process-output 関数

この関数は、Lispプログラムから特定の場面で出力の到着を明示的に許す為に用いられる。 その出力は、対応付けられたバッファに挿入されるか、フィルタ関数に与えられる。PROCESSが `nil'以外であると、この関数は、PROCESSからなんらかの出力を得るまで戻らない。

指定された2つの時間は合計され、任意のサブプロセスの出力を受け取ったどうかに関わらず、その時間だけ経過 すると`accept-process-output'は処理をemacsに戻す。この関数は、出力を得ると`nil'以外を返す。あるい は、出力が到着するまえに時間切れすると`nil'を返す。

プログラム例:httpクライアント

elispを用いたネットワークプログラミングの例として、httpクライアントを作成した。 これは、httpサーバに問い合わせて、ファイルを読み込むだけで、レンダリングもしない単純なものである。

1: (defun test-web-client ()
2:   "get file from http server"
3:   (interactive)
4:   (let ((buf (get-buffer-create "web conection"))
5:         (proc nil))
6:      (setq proc (open-network-stream
7:              "web-connection"
8:              buf
9:              "www.asahi-net.or.jp"
10:             80))
11:     (set-process-coding-system proc 'binary 'binary)
12:     (display-buffer buf)
13:     (process-send-string
14:          proc
15:          (format (concat
16:               "GET /~pw9s-szk/ HTTP/1.0\r\n"
17:               "MIME-Version: 1.0\r\n"
18:               "\r\n")))))

動作は以下の様になっている。

  1. 4行目:ローカル変数`buf'として、プロセスバッファを作成する。
  2. 5行目:プロセス用の変数`proc'をローカル変数として宣言する。
  3. 6〜10行目:`open-network-stream' 関数を用いてネットワーク 接続を開き、ローカル変数`proc'にプロセスを割り当てている。プロセスバッファとして4行目で定義した変数`buf'を指定している。
  4. 11行目:プロセスのコーディングシステムを指定している。
  5. 13行目:process-send-string 関数を用いてHttpサーバーに`GET' コマンドを送信している。サーバーより送信されたファイルの内容は、プロセスバッファ`buf'に挿入される。

参考文献


[back]

pw9s-szk@asahi-net.or.jp