Let's start Scheme

2014-09-26

簡単なサーバプログラム用フレームワーク

フレームワークというほどたいそうなものでもないのだが、何かしらサーバを書く際に唱えるおまじない部分を勝手にやってしまおうというもの。そろそろちょっとしたサーバがあると便利だよなぁという願望のもとえいや!っと書いてみた。

とりえあず、エコーサーバはこんな感じで書ける。
(import (sagittarius socket) (net server))

(define (handler socket)
  (let ((bv (socket-recv socket 255)))
    (socket-send socket bv)))

;; creates server object
(define server (make-simple-server "5000" handler))

;; start!
(start-server! server)
handlersocket-acceptで作られたソケットを受け取る。ちなみにフレームワーク側でソケットは閉じてくれるので明示的に閉じる必要はない。(閉じても特に痛くはないが)

これだけだと特にありがたみもないのだが、オプション引数で設定を取ることができる。こんな感じ。
(import (sagittarius socket) (net server))

(define (handler socket)
  (let ((bv (socket-recv socket 255)))
    (socket-send socket bv)))

;; server has daemon thread which watches :shutdown-port
;; for shutdown the server.
;; exception handler will be invoked when handler
;; raises an error.
;; given max-thread > 1 makes the server creates a
;; thread for each request. using (util concurrent)
(define config (make-server-config :shutdown-port "8888"
                                   :exception-handler (lambda (e s) (print e))
                                   :max-thread 10))

(define server (make-simple-server "5000" handler config))

(start-server! server)
上記の設定だと、最大スレッド数10、サーバを閉じる用のポート8888(この設定だとつないだ瞬間落とす)に例外ハンドラという感じになる。これ以外にもTLSソケットとかある。

(どうでもいいdesign rationale) なんでキーワード引数じゃなくconfigオブジェクトにしたかというと、こうしておくと拡張が楽かなぁという希望的観測があったからだったりする。例えばHTTPサーバを書こうと思った場合に継承してなんとかできないかぁという。どうなるかは実際に拡張を書いて見ないと分からないという・・・

ついでといっては何ではあるのだが、これを書くために(util concurrent)というJavaのjava.lang.concurrentにインスパイアされたライブラリを書いたりした(ぶっちゃけ名前だけ・・・中身は性質上にても似つかないという・・・)。中身はSRFI-18があれば限りなくR6RSポータルになっているが、SRFI-18をサポートしてる処理系の方が少ないという罠もある。

No comments:

Post a Comment