git.iko.soy/distributed-process
on ff8d9c6 help sign in
113 lines 4.3 kB history raw
1module Main where
3import Network.Transport
4import Network.Transport.TCP
6import Control.Monad
7import Data.Char
8import Data.String
9import Network.Socket (HostName, ServiceName)
10import System.Environment
12import qualified Data.ByteString.Char8 as BS
14import Debug.Trace
16type ChanId = Int
18-- | This example demonstrates how a master can be connected to slaves using
19-- the transport layer. After compiling, the following will initialize a new
20-- master that waits for two clients to connect on the local machine:
21--
22-- ./DemoTCP 127.0.0.1 8080 sourceAddrFile 2
23--
24-- Following this, two slaves should be created that will connect to the master:
25--
26-- ./DemoTCP 127.0.0.1 8081 sourceAddrFile
27-- ./DemoTCP 127.0.0.1 8082 sourceAddrFile
28--
29-- Once the connection is established, the slaves will provide the master
30-- with their SourceAddr. The master then decodes this, and sends a message
31-- back. After processing this message, the slaves respond to the master,
32-- which then outputs some data.
33main :: IO ()
34main = do
35 args <- getArgs
36 case args of
37 -- Master:
38 -- The master only provides the host, service, and slaves to expect.
39 [host, service, sourceAddrFilePath, number] -> do
40 let numSlaves = read number
41 transport <- mkTransport $ TCPConfig defaultHints host service
42 (clientSourceEnds, masterTargetEnd) <- demoMaster transport sourceAddrFilePath numSlaves
43 zipWithM_
44 (\clientSourceEnd clientId ->
45 send clientSourceEnd [BS.pack . show $ clientId])
46 clientSourceEnds [0 .. numSlaves-1]
47 replicateM_ numSlaves $ do
48 [clientMessage] <- receive masterTargetEnd
49 print clientMessage
51 closeTargetEnd masterTargetEnd
52 putStrLn "master: close connections"
54 -- Slave:
55 -- Each slave provides its own host and service, as well as details of
56 -- the master it wishes to connect to.
57 [host, service, sourceAddrFilePath] -> do
58 transport <- mkTransport $ TCPConfig defaultHints host service
59 (masterSourceEnd, slaveTargetEnd) <- demoSlave transport sourceAddrFilePath
60 [clientId] <- receive slaveTargetEnd
61 putStrLn $ "slave: received clientId: " ++ show clientId
62 let message = "Connected to slave: " ++ (BS.unpack clientId)
64 send masterSourceEnd [BS.pack message]
65 putStrLn "slave: sent message to master"
67 closeSourceEnd masterSourceEnd
68 putStrLn "slave: close connection"
70 _ -> error "Unexpected arguments"
72demoMaster :: Transport -- ^ Transport
73 -> FilePath -- ^ File to write SourceAddr
74 -> Int -- ^ Number of slaves to expect
75 -> IO ([SourceEnd], TargetEnd)
76demoMaster transport sourceAddrFilePath numSlaves = do
77 -- Establish an initial transport
78 (sourceAddr, targetEnd) <- newConnection transport
80 -- Write a file containing the sourceAddr
81 putStrLn $ "master: writing sourceAddr file:" ++ (show . serialize $ sourceAddr)
82 BS.writeFile sourceAddrFilePath $ serialize sourceAddr
84 -- Deserialize each of the sourceEnds received by the slaves
85 sourceEnds <- replicateM numSlaves $ do
86 [bytes] <- receive targetEnd
87 putStrLn "master: received connection."
88 case deserialize transport bytes of
89 Nothing -> fail "Garbage message from slave!"
90 Just sourceAddr -> connect sourceAddr
91 return (sourceEnds, targetEnd)
93demoSlave :: Transport -- ^ Transport
94 -> FilePath -- ^ File to read SourceAddr
95 -> IO (SourceEnd, TargetEnd)
96demoSlave transport masterSourceAddrFilePath = do
97 -- Create a new connection on the transport
98 (sourceAddr, targetEnd) <- newConnection transport
100 -- Establish connection with the master
101 bytes <- BS.readFile masterSourceAddrFilePath
102 case deserialize transport bytes of
103 Just masterSourceAddr -> do
104 putStrLn $ "slave: connecting to sourceAddr: " ++ (show . serialize $ masterSourceAddr)
105 masterSourceEnd <- connect masterSourceAddr
107 -- Source the serialized address of this slave
108 send masterSourceEnd [serialize sourceAddr]
109 putStrLn "slave: sent sourceAddr"
110 return (masterSourceEnd, targetEnd)
112 Nothing -> error "slave: Unable to deserialize master SourceAddr!"