为什么 ZeroMQ REQ / ROUTER 示例没有收到任何消息?

Why a ZeroMQ REQ / ROUTER Example Does Not Receive Any Message?

ZeroMQ: Messaging for Many Applications 评论 REQ -> ROUTER 通讯:

If we rewrote our “Hello World” server using ROUTER, we’d be able to process any number of “Hello” requests in parallel.

所以我从 ZeroMQ 指南中输入 hwclient.hs and have slightly modified the hwserver.hs

你好世界客户端

{-# 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

路由器:

你好世界路由器

{-# 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"

但是,当我 运行 它时,我看到客户端发送消息,但从未收到响应。

$stack exec -- client-exe
Connecting to hello world server…
Sending Hello 1…

在我的另一个 window 中,我看到服务器收到了 3 条消息,仅此而已:

$stack exec -- server-exe
Received Hello
Received Hello
Received Hello

Q1: 为什么客户端一直收不到回复?
Q2: 为什么服务器 (ROUTER) 收到 3 条消息而不是 1 条?

编辑

我更新了 hwserver.hs 以打印出它收到的消息,而不是简单地 "Hello"。

发布差异:

printf "received request: %s\n" . unpack $ buffer

已替换

putStrLn "Received Hello"

并且服务器(路由器)显示:

$stack exec -- server-exe
received request: A§
received request: 
received request: Hello

最后,这里是 send 的函数签名:

λ: :t send
send
  :: Sender t =>
     Socket z t
     -> [Flag] -> Data.ByteString.Internal.ByteString -> ZMQ z ()

反序回答...

你的3'messages'是收到消息的3帧。第一帧由 Router 套接字添加,用于标识消息的来源。第二个是 Requester 套接字添加的空分隔符帧,最后一个帧包含您发送的数据。

这就是为什么您没有收到响应的原因,当经销商套接字发送消息时,它会剥离第一个消息帧并将其用作地址来标识需要回复的客户端。由于您没有保存收到的第一帧并将其附加到传出消息,因此它会被丢弃。

遗憾的是,我对 haskell 或其 zeromq 绑定了解不够,无法为您提供代码解决方案,但如果您接收到地址缓冲区,直到读取空数据包,然后读取数据包入数据缓冲区。回复时发送地址缓冲区,空缓冲区然后回复。

根据 David's and user3666197's 的响应,我放弃了 identity 框架,我想出了:

{-# LANGUAGE OverloadedStrings #-}

-- Hello World server

module Main where

import Control.Concurrent
import Control.Monad
import System.ZMQ4.Monadic
import Text.Printf
import Data.ByteString.Char8 (unpack, pack)
import Data.List.NonEmpty

main :: IO ()
main = runZMQ $ do
    -- Socket to talk to clients
    responder <- socket Router
    bind responder "tcp://*:5555"

    forever $ do
        response @ (identity : _ : body : []) <- receiveMulti responder
        _ <- liftIO $ putStrLn . show . Prelude.length $ response
        _ <- liftIO $ forM_ response (printf "received request: %s\n" . unpack)
        liftIO $ putStrLn "sending world"
        sendMulti responder $ identity `cons` (pack "" `cons` (pack "world" :| []))

运行这

-- terminal 1
$stack exec -- client-exe
Connecting to hello world server…
Sending Hello 1…
received request: world
...

--terminal 2
$stack exec -- router-exe
3
received request: A§
received request: 
received request: Hello
sending world  
...