Shammer's Philosophy

My private adversaria

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はあまり意識していなかったな。