为什么ZeroMQ的socket.recv调用会在以下代码中挂起?

时间:2013-08-08 07:41:23

标签: f# zeromq publish-subscribe

我在ZeroMQ中遇到了一个简单的pub-sub示例的问题。我已阅读了大量文档,但似乎无法找到答案。

我从NuGet获得了libzmqclrzmq。对于套接字地址下面的两个函数是:

let sktAddr = "tcp://127.0.0.1:3456"

这是一个简单的发布者,每秒对邮件进行排队。

// Publisher - this seems to work fine
let publisher () : unit =
    let skt = (new ZMQ.Context()).Socket(ZMQ.SocketType.PUB)
    skt.SetSockOpt(ZMQ.SocketOpt.LINGER, 0)
    skt.Bind sktAddr
    skt.SendMore("TEST_TOPIC", Text.Encoding.Unicode) |> ignore
    let rec h1 () : unit =
        let nv = DateTime.Now.ToUniversalTime().ToString()
        printfn "Sending value: %s" nv
        skt.Send(Text.Encoding.Unicode.GetBytes nv) |> ignore
        Threading.Thread.Sleep 1000
        let swt = new Threading.SpinWait()
        swt.SpinOnce()
        if Console.KeyAvailable then
            match Console.ReadKey().Key with
            | ConsoleKey.Q -> ()
            | _ -> h1()
        else
            h1()
    h1()

以下简单订阅者不会抛出任何错误,但会挂在下面指定的行。

// Subscriber
let subscriber () : unit =
    let skt = (new ZMQ.Context()).Socket(ZMQ.SocketType.SUB)
    skt.Connect sktAddr
    skt.Subscribe("TEST_TOPIC", Text.Encoding.Unicode)
    let rec h1 () : unit =
        let oDat = skt.Recv() // THE PROGRAMME HANGS HERE!
        let strODat = (new Text.UnicodeEncoding()).GetString oDat
        if oDat <> null then
            printfn "Received: %s" strODat
        else
            printfn "No data received"
        let swt = new System.Threading.SpinWait()
        swt.SpinOnce()
        if Console.KeyAvailable then
            match Console.ReadKey().Key with
            | ConsoleKey.Q -> ()
            | _ -> h1()
        else
            h1()
    h1()

我已阅读this question,但未提供解决方案。所以我在这里发布一个新问题。

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:4)

我认为问题在于发布商:

skt.SendMore("TEST_TOPIC", Text.Encoding.Unicode)

不知道F#,看来上面的语句发生在循环之外。如果订阅者正在监听TEST_TOPIC,则来自发布者的任何消息都要求主题名称位于每封邮件的内容之前,因此发布者必须在每次发送时执行此操作:

skt.SendMore("TEST_TOPIC", Text.Encoding.Unicode)
skt.Send("some data here", Text.Encoding.Unicode)

..试试这个......

let publisher () : unit =
    let skt = (new ZMQ.Context()).Socket(ZMQ.SocketType.PUB)
    skt.SetSockOpt(ZMQ.SocketOpt.LINGER, 0)
    skt.Bind sktAddr

    let rec h1 () : unit =
        let nv = DateTime.Now.ToUniversalTime().ToString()
        printfn "Sending value: %s" nv
        skt.SendMore("TEST_TOPIC", Text.Encoding.Unicode) |> ignore
        skt.Send(Text.Encoding.Unicode.GetBytes nv) |> ignore
        Threading.Thread.Sleep 1000
        let swt = new Threading.SpinWait()
        swt.SpinOnce()
        if Console.KeyAvailable then
            match Console.ReadKey().Key with
            | ConsoleKey.Q -> ()
            | _ -> h1()
        else
            h1()
    h1()

..并且订阅者必须为每条消息收到两次:

// Subscriber
let subscriber () : unit =
    let skt = (new ZMQ.Context()).Socket(ZMQ.SocketType.SUB)
    skt.Connect sktAddr
    skt.Subscribe("TEST_TOPIC", Text.Encoding.Unicode)
    let rec h1 () : unit =
        let topicName = skt.Recv()
        let oDat = skt.Recv()
        let strODat = (new Text.UnicodeEncoding()).GetString oDat
        if oDat <> null then
            printfn "Received: %s" strODat
        else
            printfn "No data received"
        let swt = new System.Threading.SpinWait()
        swt.SpinOnce()
        if Console.KeyAvailable then
            match Console.ReadKey().Key with
            | ConsoleKey.Q -> ()
            | _ -> h1()
        else
            h1()
    h1()