【问题标题】:Why a ZeroMQ REQ / ROUTER Example Does Not Receive Any Message?为什么 ZeroMQ REQ / ROUTER 示例没有收到任何消息?
【发布时间】:2016-06-19 01:05:50
【问题描述】:

ZeroMQ: Messaging for Many Applicationscmets on REQ -> ROUTER 通讯:

如果我们使用 ROUTER 重写我们的“Hello World”服务器,我们将能够并行处理任意数量的“Hello”请求。

所以我输入了 hwclient.hs 并稍微修改了 ZeroMQ 指南中的 hwserver.hs

Hello World 客户端

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

还有路由器:

Hello World 路由器

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

在我的另一个窗口中,我看到服务器收到 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"

而服务器(Router)显示:

$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 ()

【问题讨论】:

  • Haskell 绑定是否自动检测和处理 API REQ/ROUTER 行为的强制部分?cit.: 一个ZMQ_REQ 套接字连接到一个ZMQ_ROUTER 套接字,除了原始对等方的身份之外,收到的每条消息应包含一个空的分隔符消息因此,应用程序看到的每个接收到的消息的整个结构变成:一个或多个 identity 部分、delimiter 部分、一个或多个 body “ )
  • 您还想了解 Pieter Hintjens 的书 [ Code Connected, Vol. 1 ], page 97 ( >>> hintjens.wdfiles.com/local--files/main%3Afiles/cc1pe.pdf ), (cit.: "worker 必须保存信封 (这是所有部分并包括空消息帧),然后它可以对数据部分执行所需的操作。请注意,REP 套接字会自动执行此操作,但我们使用的是 @ 987654348@模式... ")
  • ( cit.: 我们可以以两种不同的方式使用ROUTER: • 作为在前端和后端套接字之间切换消息的代理。 • 作为读取消息并对其进行操作。在第一种情况下,ROUTER 只是读取所有帧,包括人工身份帧,然后盲目地传递它们。在第二种情况下,ROUTER 必须知道发送的回复信封的格式。由于另一个对等方是 REQ 套接字,ROUTER 获取标识帧、空帧,然后是数据帧。"

标签: haskell zeromq


【解决方案1】:

以相反的顺序回答...

您的 3 条“消息”是收到消息的 3 帧。第一帧由Router 套接字添加,以识别消息的来源。第二个是Requester 套接字添加的空分隔符帧,最后一帧包含您发送的数据。

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

遗憾的是,我对 haskell 或其 zeromq 绑定知之甚少,无法为您提供代码解决方案,但如果您在读取空包之前接收到地址缓冲区,然后将数据包读入数据缓冲区。回复时发送地址缓冲区,一个空缓冲区,然后回复。

【讨论】:

  • when a dealer socket sends a message it strips off the first message frame and uses it as an address。试图将此知识应用于我的Req to Router 场景,我的问题是Router 不知道它必须将来自 Req 的初始HelloWorld 回复发送给谁?
  • 是的,在您的情况下,您需要获取接收到的第一帧并将其与空帧一起添加到您从路由器发送的消息中。更一般地,您应该将所有帧(包括空帧)以相同的顺序添加到传出消息中,这将允许您链接路由器。
  • 多帧和多部分的意思一样吗?
  • 是的。由于添加了路由信息,所有发送到路由器套接字的消息都以多帧/多部分的形式结束。
【解决方案2】:

对于 David'suser3666197'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  
...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-09
    相关资源
    最近更新 更多