@@ -6,7 +6,7 @@ import Control.Monad
7import Data.Int
7import Data.Int
8import Network.Socket
8import Network.Socket
9− ( AddrInfoFlag (AI_PASSIVE), HostName, ServiceName, Socket
9+ ( AddrInfo, AddrInfoFlag (AI_PASSIVE), HostName, ServiceName, Socket
10 , SocketType (Stream), SocketOption (ReuseAddr)
10 , SocketType (Stream), SocketOption (ReuseAddr)
11 , accept, addrAddress, addrFlags, addrFamily, bindSocket, defaultProtocol
11 , accept, addrAddress, addrFlags, addrFamily, bindSocket, defaultProtocol
12 , defaultHints
12 , defaultHints
@@ -27,11 +27,14 @@ import Data.ByteString.Internal as BSI
27import Foreign.Storable (pokeByteOff, peekByteOff)
27import Foreign.Storable (pokeByteOff, peekByteOff)
28import Foreign.C (CInt(..))
28import Foreign.C (CInt(..))
29import Foreign.ForeignPtr (withForeignPtr)
29import Foreign.ForeignPtr (withForeignPtr)
30+import Control.Concurrent.Chan (Chan, newChan, readChan, writeChan)
31foreign import ccall unsafe "htonl" htonl :: CInt -> CInt
32foreign import ccall unsafe "htonl" htonl :: CInt -> CInt
32foreign import ccall unsafe "ntohl" ntohl :: CInt -> CInt
33foreign import ccall unsafe "ntohl" ntohl :: CInt -> CInt
34−main :: IO ()
35+passive :: Maybe AddrInfo
36+passive = Just (defaultHints { addrFlags = [AI_PASSIVE] })
36 [pingsStr] <- getArgs
39 [pingsStr] <- getArgs
37 serverReady <- newEmptyMVar
40 serverReady <- newEmptyMVar
@@ -39,50 +42,44 @@ main = do
40 -- Start the server
43 -- Start the server
41 forkIO $ do
44 forkIO $ do
42− putStrLn "server: creating TCP connection"
45+ -- Initialize the server
43− serverAddrs <- getAddrInfo
46+ serverAddr:_ <- getAddrInfo passive Nothing (Just "8080")
44− (Just (defaultHints { addrFlags = [AI_PASSIVE] } ))
47− let serverAddr = head serverAddrs
48− sock <- socket (addrFamily serverAddr) Stream defaultProtocol
47+ sock <- socket (addrFamily serverAddr) Stream defaultProtocol
49 setSocketOption sock ReuseAddr 1
48 setSocketOption sock ReuseAddr 1
50 bindSocket sock (addrAddress serverAddr)
49 bindSocket sock (addrAddress serverAddr)
52− putStrLn "server: awaiting client connection"
53− putMVar serverReady ()
54 listen sock 1
50 listen sock 1
55− (clientSock, clientAddr) <- accept sock
57− -- Set up an mvar that we will listen on and echo to the client
52+ -- Set up multiplexing channel
58− mvar <- newEmptyMVar
53+ multiplexMVar <- newEmptyMVar
59− forkIO $ forever $ do
63− -- Read from the client and output on the channel
55+ -- Wait for incoming connections (pings from the client)
64− putStrLn "server: listening for pings"
56+ putMVar serverReady ()
65− pong clientSock mvar
57+ (clientSock, pingAddr) <- accept sock
58+ forkIO $ socketToMVar clientSock multiplexMVar
60+ -- Reply to the client
61+ forever $ takeMVar multiplexMVar >>= send clientSock
67 -- Start the client
63 -- Start the client
68 forkIO $ do
64 forkIO $ do
69 takeMVar serverReady
65 takeMVar serverReady
70− let pings = read pingsStr
66+ serverAddr:_ <- getAddrInfo Nothing (Just "127.0.0.1") (Just "8080")
71− serverAddrs <- getAddrInfo
75− let serverAddr = head serverAddrs
76− sock <- socket (addrFamily serverAddr) Stream defaultProtocol
67+ clientSock <- socket (addrFamily serverAddr) Stream defaultProtocol
78− N.connect sock (addrAddress serverAddr)
68+ N.connect clientSock (addrAddress serverAddr)
79−
69+ ping clientSock (read pingsStr)
81 putMVar clientDone ()
70 putMVar clientDone ()
83 -- Wait for the client to finish
72 -- Wait for the client to finish
84 takeMVar clientDone
73 takeMVar clientDone
75+socketToMVar :: Socket -> MVar ByteString -> IO ()
76+socketToMVar sock mvar = go
78+ go = do bs <- recv sock
79+ when (BS.length bs > 0) $ do
86pingMessage :: ByteString
83pingMessage :: ByteString
87pingMessage = pack "ping123"
84pingMessage = pack "ping123"
@@ -95,29 +92,21 @@ ping sock pings = go pings
95 go !i = do
92 go !i = do
96 before <- getCurrentTime
93 before <- getCurrentTime
97 send sock pingMessage
94 send sock pingMessage
98− bs <- recv sock 8
95+ bs <- recv sock
99 after <- getCurrentTime
96 after <- getCurrentTime
100 -- putStrLn $ "client received " ++ unpack bs
97 -- putStrLn $ "client received " ++ unpack bs
101 let latency = (1e6 :: Double) * realToFrac (diffUTCTime after before)
98 let latency = (1e6 :: Double) * realToFrac (diffUTCTime after before)
102 hPutStrLn stderr $ show i ++ " " ++ show latency
99 hPutStrLn stderr $ show i ++ " " ++ show latency
103 go (i - 1)
100 go (i - 1)
105−pong :: Socket -> MVar ByteString -> IO ()
102+-- | Receive a package
108− -- putStrLn $ "server received " ++ unpack bs
109− when (BS.length bs > 0) $ do
113−-- | Wrapper around NBS.recv (for profiling)
114−recv :: Socket -> Int -> IO ByteString
103+recv :: Socket -> IO ByteString
115−recv sock _ = do
104+recv sock = do
116 header <- NBS.recv sock 4
105 header <- NBS.recv sock 4
117 length <- decodeLength header
106 length <- decodeLength header
118 NBS.recv sock (fromIntegral (length :: Int32))
107 NBS.recv sock (fromIntegral (length :: Int32))
120−-- | Wrapper around NBS.send (for profiling)
109+-- | Send a package
121send :: Socket -> ByteString -> IO ()
110send :: Socket -> ByteString -> IO ()
122send sock bs = do
111send sock bs = do
123 length <- encodeLength (fromIntegral (BS.length bs))
112 length <- encodeLength (fromIntegral (BS.length bs))