-- $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 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 s = do (s', clientAddr) <- accept s 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 19 -- if (i >= 19) putStr ("Server recv: " ++ str) if ((length str) >= 19) then do putStr ("Server read: " ++ str) -- writ <- writeSocket sock str writ <- send sock str putStr ("Server wrote: " ++ str) -- read_data sock $! (totalbytes+(length $! str)) -- read_data sock (totalbytes+(length str)) else do putStr ("server read: " ++ str) return totalbytes local = "127.0.0.1" message = "Hello there sailor\n" 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 putStr ("Client wrote: " ++ message) -- -- (str,i) <- readSocket sock 19 str <- recv sock 19 if (str /= message) then do putStr ("Client read error: " ++ str ++ "\n") exitFailure else do putStr ("Client read success") server_echo sock (n-1) else do putStr "Client read nil\n" 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 putStr("join s") join c putStr("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