SMLでSocketプログラミング
SMLのBasisライブラリにはBSD-Socketのインターフェースが含まれている*1 ので使ってみました.
以下にサーバ側で待ち受けるソケットを作る箇所を示します.
structure S = Socket structure N = INetSock infix >>= fun op>>= (NONE ,_) = NONE | op>>= (SOME s,f) = f s fun makeAddr (host:string) (port:int) : N.sock_addr option = let val addr = (NetHostDB.getByName host) >>= (fn addr => SOME(N.toAddr(NetHostDB.addr addr, port))) in addr end fun server_socket (host:string) (port:int) : S.passive N.stream_sock option = let val addr = makeAddr host port val sock = N.TCP.socket() in addr >>= (fn addr' => (S.Ctl.setREUSEADDR (sock, true) (* SML/njだと不調? *) ;S.bind (sock, addr') ;S.listen (sock, 5) ;SOME sock)) end
unitだらけで非常に気持ち悪いですね. うへぇ….
続いて,エコーサーバの実行
fun echo_server sock = let val s = #1 (accept sock) fun loop () = let val recv_ = recvVec(s, 256) in if Word8Vector.length(recv_)=0 then SOME s else loop() before ignore(sendVec(s, Word8VectorSlice.full recv_)) end in loop () handle SysErr => NONE end val _ = (server_socket "localhost" 2000) >>= echo_server >>= close_socket
非常に簡潔です.
まとめ
*1:例によってオプショナルな扱いなワケですが…