Shammer's Philosophy

My private adversaria

client socket handling macro

with-open-passive-socket ver 20120327 - Shammerismの処理では accept したクライアントの処理を普通に書いていたが、

  1. accept される
  2. read する
  3. close する

という一般的すぎる流れ。read の直後の処理はケースバイケースかもしれないが、accept されるところと close するところはもう定型なので、これを macro にしてしまう。

(defmacro handle-accept-connections (&rest body)
  (let ((server-symbol (caar body))
	(client-symbol (cadar body))
	(actions (cdr body)))
    `(let ((,client-symbol (accept-client-socket ,server-symbol)))
       (unwind-protect
	    (progn
	      ,@actions)
	 (close-client-socket ,client-symbol)))))

これを使って echo-server を再定義。

(defun open-echo-server-v2 (addr port)
  (format t "> OpenEchoServer port open...~%")
  (with-open-passive-socket (server addr port)
    (handle-accept-connections (server client)
			       (let ((receive-buffer (make-array 0 :fill-pointer 0 :adjustable t :element-type '(unsigned-byte 8))))
				 (do () (nil)
				   (let ((b (read-byte client nil 'eof)))
				     (cond ((eql 'eof b)
					    (return))
					   (t
					    (vector-push-extend b receive-buffer)))
				     (format t "~A " b)
				     (when (equal b 10)
				       (return))))
				 (let ((received-message (decode-string-from-octets receive-buffer :external-format :utf-8)))
				   (format t "~A~%" received-message)
				   (when (string-equal received-message "quit")
				     (format t "received quit...~%")
				     (quit)))))))

データの読み込みまで macro でもいいのかもしれない。binary データお読み込むものと ascii データを読み取るもの、2 パターン書いてみようか。。。