LispでClientSocket(?)作成
LispでServerSocketを作成する方法は試したので、今度はそれに接続するClient側のSocketを書いてみる。
ServerSocketはこんな感じの関数にしてみた。
(defun open-server-socket (port) (let ((server (make-socket :type :stream :connect :passive :local-host "localhost" :local-port port))) (let ((client-socket (accept-connection server))) (close client-socket)) (close server)))
この実装だとまだ何もしないが、ひとまずこれでOK。
これに接続するクライアント側は、Clozure CL Documentationを参考にすると
?(setf client (make-socket :address-family :internet :type :stream :connect :active :remote-host "localhost" :remote-port '7001))
という感じかな。ではお立ち会い・・・
?(open-server-socket '7001)
よし。とりあえず無応答で、Listenだけしているものと思われる。netstatをとると、
$ netstat -an | grep 7001 tcp4 0 0 127.0.0.1.7001 *.* LISTEN
と、期待通り。ここで、先に書いたクライアントのmake-socketを実行する。
? (setf client (make-socket :address-family :internet :type :stream :connect :active :remote-host "localhost" :remote-port '7001)) #<BASIC-TCP-STREAM ISO-8859-1 (SOCKET/7) #xC4C92B6> ?
サーバー側は、
?(open-server-socket '7001) T ?
となった。ここでnetstatをまたとってみる。
$ netstat -an | grep 7001 tcp4 0 0 127.0.0.1.49793 127.0.0.1.7001 CLOSE_WAIT tcp4 0 0 127.0.0.1.7001 127.0.0.1.49793 FIN_WAIT_2 $
次に、クライアント側をクローズしてみる。
?(close client) T
netstat はこうなった。
$ netstat -an | grep 7001 tcp4 0 0 127.0.0.1.7001 127.0.0.1.49793 TIME_WAIT $
なるほど。とりあえず、任意のサーバへ接続する処理は問題なさそうだ。
Socketの動作についても少し勉強になった。
サーバー側で、特に何もしないでクライアントとやり取りするSocketをすぐにクローズする実装になっているから、クライアント側から接続が来たらすぐにTを返して終了する。FINを送ったクライアントは、相手からのFINを待つ間はFIN_WAIT_2になるようだ。そして、FINを受け取ったSocketは、アプリ側からcloseされるまでCLOSE_WAITになる。CLOSE_WAITがTIME_WAITになるのはエフェメラレルポートのバッティングを防ぐため。TIME_WAITは知っていたけれど、FIN_WAIT_2はあまり意識していなかったな。