-- $Id: echo.ghc,v 1.2 2001/05/01 20:19:52 doug Exp $ -- http://www.bagley.org/~doug/shootout/ -- Haskell echo/client server -- written by Brian Gregor -- compile with: -- ghc -O -o echo -package net -package concurrent -package lang echo.hs module Main where import SocketPrim import Concurrent import System (getArgs,exitFailure) import Exception(finally) import MVar import IO server_sock :: IO (Socket) server_sock = do s <- socket AF_INET Stream 6 setSocketOption s ReuseAddr 1 -- bindSocket s (SockAddrInet (mkPortNumber portnum) iNADDR_ANY) bindSocket s (SockAddrInet (PortNum portnum) iNADDR_ANY) listen s 2 return s echo_server :: Socket -> IO () echo_server s = do (s', clientAddr) <- accept s h <- socketToHandle s' ReadWriteMode proc <- read_data s' 0 putStrLn ("server processed "++(show proc)++" bytes") sClose s' where read_data sock totalbytes = do -- (str,i) <- readSocket sock 19 str <- recv sock 18 -- if (i >= 19) putStrLn ("Server recv: " ++ str) if ((length str) >= 18) then do putStrLn ("Server read: " ++ str) -- writ <- writeSocket sock str writ <- send sock str putStrLn ("Server wrote: " ++ str) -- read_data sock $! (totalbytes+(length $! str)) -- read_data sock (totalbytes+(length str)) else do putStrLn ("server read: " ++ str) return totalbytes local = "127.0.0.1" message = "Hello there sailor" portnum = 7001 client_sock = do s <- socket AF_INET Stream 6 ia <- inet_addr local -- connect s (SockAddrInet (mkPortNumber portnum) ia) connect s (SockAddrInet (PortNum portnum) ia) return s echo_client n = do s <- client_sock drop <- server_echo s n sClose s where server_echo sock n = if n > 0 then do -- writeSocket sock message send sock message putStrLn ("Client wrote: " ++ message) -- -- (str,i) <- readSocket sock 19 str <- recv sock 19 if (str /= message) then do putStrLn ("Client read error: " ++ str) exitFailure else do putStrLn ("Client read success") server_echo sock (n-1) else do putStrLn "Client read nil" return [] main = do ~[n] <- getArgs -- server & client semaphores -- get the server socket ssock <- server_sock -- fork off the server s <- myForkIO (echo_server ssock) -- fork off the client c <- myForkIO (echo_client (read n::Int)) -- let 'em run until they've signaled they're done join s putStrLn "join s" join c putStrLn "join c" -- these are used to make the main thread wait until -- the child threads have exited myForkIO :: IO () -> IO (MVar ()) myForkIO io = do mvar <- newEmptyMVar forkIO (io `finally` putMVar mvar ()) return mvar join :: MVar () -> IO () join mvar = readMVar mvar