\begin{code}
module Main where
import Control.Concurrent
import Network
import System.IO
type Service = String -> String
port :: PortNumber
port = 8888
echo :: Service
echo = id
main :: IO ()
main = server port echo
server :: PortNumber -> Service -> IO ()
server p sc = withSocketsDo $ listenOn (PortNumber p) >>= serve sc
serve :: Service -> Socket -> IO ()
serve sc sock = accept sock >>= forkIO . service sc >> serve sc sock
service :: Service -> (Handle, HostName, PortNumber) -> IO ()
service sc (h,_,_) = hSetBuffering h LineBuffering >> loop h sc
loop :: Handle -> Service -> IO ()
loop h sc = hIfEOF h (return ()) $ hGetLine h >>= hPutStrLn h . sc >> loop h sc
hIfEOF :: Handle -> IO a -> IO a -> IO a
hIfEOF h t e = hIsEOF h >>= \ eof -> if eof then t else e
\end{code}
私の環境では上記のHigh Level API利用だとservname no supportedになる。 アドレス解決ができない模様なのでLow Level APIを叩いてみた。cut-sea:2008/06/05 05:24:09 JST
import Network.Socket
server sv = do s0 <- sock0
bindSocket s0 addr0
listen s0 5
(s1,a1) <- accept s0
sv s1
where
sock0 = socket AF_INET Stream 0
addr0 = SockAddrInet 8888 0x0100007f -- 127.0.0.1:8888
echo s = do (rcv, len, addr) <- recvFrom s 2048
send s rcv
echo s
main :: IO a
main = server echo
なぜかIP Addressの指定が1.0.0.127的にしないと127.0.0.1にならない。
もしかしてBig/Little Endianがおかしい?(pkgsrcからbuildしたghcなんだけど)
正直流れが見えるまで、何故こんなAPIになってるのかムカついてたんだけど…
ステップバイステップでないと書けない子なので、
sock0 = socket AF_INET Stream 0
addr0 = SockAddrInet 8888 0x0100007f -- 127.0.0.1:8888
:
:
みたいな調子でロードしてはsock0やらaddr0やら確認してた。 するとbindとlistenのところでハマって、 ようやくsocketの返すのがIO Socketという風にIOモナドに包まれている理由が分った。 なーる。