ネットワークプログラミング(サーバー編)

そろそろネットワークのプログラムを書いてみようと思ったので、echo サーバを書いてみた。

意外に簡単に書けてしまった。 C しか知らなかった頃は、頑張って scoket, bind, listen ... とかシステムコール呼び出してたけど(あと引数の構造体を作るのが面倒だった記憶が)、もうそんなことをしなくてもいいんだ。

コードはこんな感じ。セッションが終了すると、サーバも終了してしまうが、まあ、そこはおいおいということで。

import Network
import System.IO
import System.Environment
import Control.Applicative

main :: IO ()
main = do
    port           <- (!! 0) <$> getArgs
    sock           <- listenOn . PortNumber . fromInteger $ read port
    (handle, _, _) <- accept sock
    hSetBuffering handle LineBuffering
    request        <- hGetContents handle
    hPutStr handle request
    sClose sock

驚いたのが、

    request        <- hGetContents handle
    hPutStr handle request

の部分。バッファリングは行単位にしているので、hGetContents で得られるデータは 1 行だけ。hGetContents の後に hPutStr でその 1 行を出力している。

なので、このエコーサーバは 1 行のみ結果を返して終了するだろうと思っていたのだが、実際は違った。セッションが終了するまで、何行でもエコーを返してくる。しかも、クライアントが 1 行入力する度にサーバも 1 行返してくる(セッション終了時に、今まで入力した行をまとめて返してくるということではない)。

遅延評価ってやつかしら?すごいな。

ちなみに、ログを出力しようと、hGetContents handle と hPutStr handle request の間に putStrLn を挟んだら期待通りには動かなくなった。まともなサーバにするにはこんなコードではダメ(わかってるけど)。