Skip to content

Instantly share code, notes, and snippets.

@Tehnix
Created July 12, 2016 19:28
Show Gist options
  • Save Tehnix/b246f1a73d30107ea59659dba09f9ec3 to your computer and use it in GitHub Desktop.
Save Tehnix/b246f1a73d30107ea59659dba09f9ec3 to your computer and use it in GitHub Desktop.
Example of networking with a server and client (as bonus it also uses forkIO for threading and MVar's for thread communication).
module Main where
import Control.Monad (unless)
import Network.Socket hiding (recv)
import qualified Data.ByteString as S
import qualified Data.ByteString.Char8 as C
import Network.Socket.ByteString (recv, sendAll)
import Control.Concurrent (forkIO)
import Control.Concurrent.MVar (takeMVar, putMVar, newEmptyMVar, MVar)
portNumber :: Integer
portNumber = 3000
main :: IO ()
main = do
-- Control when to start the client, and when to shut down the program
serverHasStarted <- newEmptyMVar
serverHasClosed <- newEmptyMVar
-- Run the server in a thread
putStrLn $ ">> Running server in a thread on port " ++ show portNumber ++ "..."
forkIO $ runTestServer serverHasStarted serverHasClosed
-- Start the client when the server has started, by waiting for
-- the MVar `serverHasStarted`
takeMVar serverHasStarted
putStrLn $ ">> The server has started!"
putStrLn $ ">> Starting client on port " ++ show portNumber ++ "..."
runTestClient
-- Make sure the server has closed properly by waiting for the MVar
-- `serverHasClosed`
takeMVar serverHasClosed
runTestServer :: MVar () -> MVar () -> IO ()
runTestServer hasStarted hasClosed = do
withSocketsDo $
do addrinfos <- getAddrInfo
(Just (defaultHints {addrFlags = [AI_PASSIVE]}))
Nothing (Just (show portNumber))
let serveraddr = head addrinfos
sock <- socket (addrFamily serveraddr) Stream defaultProtocol
bindSocket sock (addrAddress serveraddr)
listen sock 1
putMVar hasStarted ()
(conn, _) <- accept sock
talk conn
sClose conn
sClose sock
putMVar hasClosed ()
where
talk :: Socket -> IO ()
talk conn =
do msg <- recv conn 1024
unless (S.null msg) $ sendAll conn msg >> talk conn
runTestClient :: IO ()
runTestClient = do
withSocketsDo $
do addrinfos <- getAddrInfo Nothing (Just "") (Just (show portNumber))
let serveraddr = head addrinfos
sock <- socket (addrFamily serveraddr) Stream defaultProtocol
connect sock (addrAddress serveraddr)
sendAll sock $ C.pack "Hello, world!"
msg <- recv sock 1024
sClose sock
putStr "Received "
C.putStrLn msg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment