LoginSignup
13
11

More than 5 years have passed since last update.

Emacsでソケット通信

Posted at

EmacsでEcho Serverを作る例( http://www.emacswiki.org/emacs/EmacsEchoServer )
があったので逆にクライアントを作ってみた。
きっとこの程度の例ならどっかに残ってるとは思うけど練習。
Echo Clientをつくるだけなのもアレなので簡易fetchを作ってみた。

ホスト名と取得するパスを指定してHTTPで簡易的に取ってくる。

myfetch.el
(defvar myfetch-name "myfetch")
(defvar myfetch-buffer-name "*myfetch output*")
(defvar myfetch-buffer nil)

(defun myfetch (host file)
  (interactive "sHost: \nsFile: ")
  (unless (process-status myfetch-name)
    (setq myfetch-buffer (get-buffer-create myfetch-buffer-name))
    (let ((proc (make-network-process :name myfetch-name
                     :buffer myfetch-buffer
                     :family 'ipv4
                     :host host
                     :service 80
                     :sentinel 'myfetch-sentinel
                     :nowait nil
                     :filter 'myfetch-filter :server nil)))
      (myfetch-logging
       (format "Access to http://%s:80/%s" host file))
      (myfetch-logging "Make connection...")
      (process-send-string
       proc (format "GET /%s HTTP/1.0\r\n\r\n" file)))))

(defun myfetch-filter (proc string)
  (myfetch-logging string))

(defun myfetch-sentinel (proc msg)
  (myfetch-logging (format "sentinel: proc=%s msg=%s" proc msg)))

(defun myfetch-logging (string)
  (when (get-buffer myfetch-buffer)
    (with-current-buffer myfetch-buffer
      (goto-char (point-max))
      (insert (current-time-string)
          " " string)
      (newline))))

localhostのApacheにアクセスした結果は以下の通り。
おぉちゃんと返ってきてる。

Mon May 20 00:24:39 2013 Access to http://localhost:80/index.html
Mon May 20 00:24:39 2013 Make connection...
Mon May 20 00:24:41 2013 HTTP/1.1 200 OK
Date: Sun, 19 May 2013 15:24:40 GMT
Server: Apache/1.3.41 (Darwin) PHP/4.4.9 mod_perl/1.29 mod_ssl/2.8.31 OpenSSL/0.9.7l
Content-Location: index.html.en
Vary: negotiate,accept-language,accept-charset
TCN: choice
Last-Modified: Fri, 04 May 2001 00:00:38 GMT
ETag: "39216-5b0-3af1f126;4d11e7c5"
Accept-Ranges: bytes
Content-Length: 1456
Connection: close
Content-Type: text/html
Content-Language: en
Expires: Sun, 19 May 2013 15:24:40 GMT

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>

...中略...

</body>
</html>


Mon May 20 00:24:41 2013 sentinel: proc=myfetch msg=connection broken by remote peer

例の流れ

  1. make-network-process で通信するプロセスを作成
  2. process-send-string で送信
  3. 受信はfilter(コールバック関数、例では myfetch-filter )で処理

番兵(sentinel)は、何かプロセスに変化が起きたとき(死んだときとか)に呼ばれるコールバック関数

終了処理

delete-process ってのがある。これはプロセスを殺して直ちに忘れてしまう。実際、例のmyfetch-filterの最後にこいつを挟んでみたところちょっと長いページだと途中で切れた。まあ当たり前か。

今回は、サーバから切断してくれるけど何もしなくて良いのかな?番兵は切断を関知しているっぽいけど。

make-network-processとopen-network-stream

手元にあった通信してそうなemacs lispを斜め読みしていたら通信を始める手続きとして
make-network-processopen-network-stream の2種類があった。
なお、 make-network-process の方はEmacs 22以上のみらしい。
(実際mewのソースには前者が使えなかったら後者を使うようです。)

make-network-processopen-network-stream よりも低レベルなネットワークを扱えるらしい。

make-network-processについてもう少し深く

ほとんどマニュアルの訳になってますケド…

ネットワークコネクションを作成、もしくは、サーバを作成する手続き。戻り
値はプロセスオブジェクト。引数はkeyword/argumentリスト

keyword description
:name プロセスに使用する名前。ユニーク
:buffer プロセスの出力をするバッファ。nilも可。
:host ホスト名。文字列かlocalhostを表すシンボル 'local
:service クライアントではつなぐ先のポート番号。サーバではlistenするポート番号。tを指定すると適当に選ばれる
:type nil (stream; default) / datagram ?
:family local / ipv4 / ipv6
:nowait BOOL ストリーム通信においてnon-nilを指定するとnon-blockingになる
:filter フィルタ関数
:sentinel 番兵関数

後半から適当だし説明してないオプション沢山あるけどよく分からないのでパス

参考

13
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
11