ZeroMQ: Messaging for Many Applications comments on REQ -> ROUTER
communication:
If we rewrote our “Hello World” server using
ROUTER
, we’d be able to process any number of “Hello” requests in parallel.
So I typed out hwclient.hs
and have slightly modified the hwserver.hs
from the ZeroMQ Guide:
Hello World Client
{-# LANGUAGE OverloadedStrings #-}
-- Hello World client
module Main where
import Control.Monad
import System.ZMQ4.Monadic
main :: IO ()
main = runZMQ $ do
liftIO $ putStrLn "Connecting to hello world server…"
requester <- socket Req
connect requester "tcp://localhost:5555"
forM_ [1..10] $ \i -> do
liftIO . putStrLn $ "Sending Hello " ++ show i ++ "…"
send requester [] "Hello"
_ <- receive requester
liftIO . putStrLn $ "Received World " ++ show i
And the Router:
Hello World Router
{-# LANGUAGE OverloadedStrings #-}
-- Hello World server
module Main where
import Control.Concurrent
import Control.Monad
import System.ZMQ4.Monadic
main :: IO ()
main = runZMQ $ do
-- Socket to talk to clients
responder <- socket Router
bind responder "tcp://*:5555"
forever $ do
buffer <- receive responder
liftIO $ do
putStrLn "Received Hello"
threadDelay 1000000 -- Do some 'work'
send responder [] "World"
But, when I run it, I see the client send a message, but never receive a response.
$stack exec -- client-exe
Connecting to hello world server…
Sending Hello 1…
In my other window, I see the server receives 3 messages and nothing more:
$stack exec -- server-exe
Received Hello
Received Hello
Received Hello
Q1:
Why does the client never receive a reply?Q2:
And why does the server (ROUTER
) receive 3 messages rather than 1?
EDIT
I updated hwserver.hs
to print out the messages that it receives rather than simply "Hello".
Posting the diff:
printf "received request: %s\n" . unpack $ buffer
replaced
putStrLn "Received Hello"
And the server (Router) showed:
$stack exec -- server-exe
received request: A§
received request:
received request: Hello
Lastly, here's the send
's function signature:
λ: :t send
send
:: Sender t =>
Socket z t
-> [Flag] -> Data.ByteString.Internal.ByteString -> ZMQ z ()
REQ/ROUTER
behaviour automatically? (cit.: "When aZMQ_REQ
socket is connected to aZMQ_ROUTER
socket, in addition to the identity of the originating peer each message received shall contain an empty delimiter message part. Hence, the entire structure of each received message as seen by the application becomes: one or more identity parts, delimiter part, one or more body parts. When sending replies to aZMQ_REQ
socket the application must include the delimiter part." ) – user3666197worker
has to save the envelope ( which is all the parts up to and including the empty message frame ) and then it can do what’ s needed with the data part. Note that aREP
socket would do this automatically, but we’ re using theREQ-ROUTER
pattern ... " ) – user3666197ROUTER
in two distinct ways: • As a proxy that switches messages between frontend and backend sockets. • As an application that reads the message and acts on it. In the first case, theROUTER
simply reads all frames, including the artificial identity frame, and passes them on blindly. In the second case theROUTER
must know the format of the reply envelope it’ s being sent. As the other peer is aREQ
socket, theROUTER
gets the identity frame, an empty frame, and then the data frame." – user3666197