繁体   English   中英

ZeroMQ中的PUB / SUB模式不起作用

[英]PUB/SUB pattern in ZeroMQ not working

我正在尝试使用ZeroMQ实现非常基本的PUB/SUB模式。 我希望有一台服务器(始终处于活动状态)向所有客户端广播消息(发布者),并且不关心已连接的客户端。 如果客户端以订户身份连接到此服务器,则它应收到该消息。

但是,我无法使用PUB/SUB发送消息。

在Python中将是:

# publisher (server.py)
import zmq

ctx = zmq.Context()
publisher = ctx.socket(zmq.PUB)
publisher.bind('tcp://127.0.0.1:9091')

while True:
    publisher.send_string("test")

# subscriber (client.py)
import zmq

ctx = zmq.Context()
subscriber = ctx.socket(zmq.SUB)
subscriber.connect('tcp://127.0.0.1:9091')

while True:
    msg = subscriber.recv_string()
    print msg

或在golang中:

package main

import (
    "github.com/pebbe/zmq4"
    "log"
    "time"
)

func Listen(subscriber *zmq4.Socket) {
    for {
        s, err := subscriber.Recv(0)
        if err != nil {
            log.Println(err)
            continue
        }
        log.Println("rec", s)
    }
}

func main() {
    publisher, _ := zmq4.NewSocket(zmq4.PUB)
    defer publisher.Close()
    publisher.Bind("tcp://*:9090")

    subscriber, _ := zmq4.NewSocket(zmq4.SUB)
    defer subscriber.Close()
    subscriber.Connect("tcp://127.0.0.1:9090")

    go Listen(subscriber)
    for _ = range time.Tick(time.Second) {
        publisher.Send("test", 0)
        log.Println("send", "test")

    }
}

连接时我是否误解了这种模式,还是需要从客户端向服务器发送特定信号? 我对golang版本感兴趣,仅使用python版本进行测试。

我是否误解了这种模式? 是的,幸运的是您做到了。

ZeroMQ原型被定义为代表某种行为。 至于说, PUSH -archetype存取点“到”所有迄今建立沟通渠道推动每一个消息, PULL -er存取点拉什么,已经到达了线(县)“它的手”, PUB -lisher存取点公布, SUB - scriber AccessPoint进行订阅,以便仅接收与其主题过滤器匹配的消息,但不匹配其他任何消息。

显然,这种原型“规范”有助于构建ZeroMQ智能消息传递/信令基础结构,以使我们易于在体系结构中使用。


# subscriber (client.py)
import zmq

ctx        = zmq.Context()
subscriber = ctx.socket( zmq.SUB )
subscriber.connect( 'tcp://127.0.0.1:9091' )
subscriber.setsockopt( zmq.LINGER,    0 )         # ALWAYS:
subscriber.setsockopt( zmq.SUBSCRIBE, "" )        # OTHERWISE NOTHING DELIVERED

while True:
    msg = subscriber.recv_string()                # MAY USE .poll() + zmq.NOBLOCK
    print msg

subscriber, _ := zmq4.NewSocket( zmq4.SUB )
subscriber.Connect(             "tcp://127.0.0.1:9090" )
subscriber.SetSubscribe(         filter )                 // SET: <topic-filter>

subscriber.SetLinger(            0 )    //  SAFETY FIRST: PREVENT DEADLOCK
defer subscriber.Close()                //  NOW MAY SAFELY SET:

...
msg, _ := subscriber.Recv( 0 )

根据定义,任何右实例化的SUB AccessPoint对象实际上都有零机会知道,什么消息是那些正确消息的选择是什么,因此应该“传递”这些消息而不是什么消息。

如果没有这一块初步知识,ZeroMQ设计师有一个主要的选择是要么原型政策一致,让PUB侧的接入节点,来分配所有的.send() -acquired消息只对那些SUB侧的接入节点(S),有明确要求接收任何这样的,对通过zmq.SUBSCRIBE -mechanics 提供了从发送PUB也给所有迄今未决定的SUB -s。

前者是ZeroMQ作者的一致而专业的设计步骤。
后者实际上意味着违反ZeroMQ自己的RFC规范。

后一种选择就像是有人刚搬到新公寓,几乎不会期望从第二天早上开始,所有报纸和杂志都出现在新邮箱中,是吗? 但是,如果有人订阅《波士顿环球报》,则第二天早晨,新发行版将在门口,因为它将继续留在那儿,直到有人取消订阅,报纸破产或缺少纸卷而阻止印刷厂交付为止在适当的时间和方式,或者Big Dig隧道中的交通拥堵可能会在某一天造成全部或仅本地交付的麻烦。

所有这一切都是自然的,并且与原型策略兼容。

Intermezzo: Golang已经绑定到许多不同的API版本
技术纯粹主义者在这里会反对,早期的API版本(直到一些v3.2 +版本)实际上确实将所有消息有效负载从PUB传输到所有SUB -s,因为它简化了PUB端的工作量范围,但增加了传输类( es)数据流和SUB端资源/延迟的主题过滤器处理。 然而,就API抽象的观点而言,所有这些都对用户代码不可见。 因此,除了需要适当扩展资源外,这对用户是透明的。 最新的API版本恢复了主题过滤器处理器的角色,现在让它在PUB端发生。 尽管如此,在两种情况下,ZeroMQ RFC规范策略都是以这种方式实现的, SUB端永远不会(通过.recv()传递与有效的显式SUB端不匹配的单个消息。认购(S)

在所有情况下, SUB zmq.SUBSCRIBE尚未显式设置任何zmq.SUBSCRIBE指示的主题过滤器, 它不能也不会提供任何内容 (这是自然的,并且与为SUB定义的ZeroMQ RFC Archetype-policy完全一致-键入AccessPoint)。

最佳下一步:

至少始终要阅读ZeroMQ API文档,该文档中的所有详细信息都是经过专业指定的-至少,这样的用户至少可以一窥智能消息传递/信令框架的气息。

这将不会帮助任何人从绿色领域开始,并完全建立自己复杂的思维概念,并且对所有事物在内部如何工作有深入的了解,这显然不是任何API文档的野心,对吗? 但是,一旦掌握了ZeroMQ内部架构(如在下一段中提到的源中所述),这将帮助任何人刷新或提醒所有可配置的细节。

另外,对于确实对感兴趣或仅每秒人来说,花时间和精力来始终阅读Pieter HINTJENS的著作“ Code Connected,Volume 1”(可免费以pdf格式)以及任何其他书籍,这是值得的。之所以选择他的书,是因为他后来在软件工程方面的丰富经验,因为他对现代计算的许多见识可能并且将会激发很多。

编辑:

GO中的MWE

package main

import (
    "github.com/pebbe/zmq4"
    "log"
    "time"
)

func Listen(subscriber *zmq4.Socket) {
    for {
        s, err := subscriber.Recv(0)
        if err != nil {
            log.Println(err)
            continue
        }
        log.Println("rec", s)
    }
}

func main() {
    publisher, _ := zmq4.NewSocket(zmq4.PUB)
    publisher.SetLinger(0)
    defer publisher.Close()

    publisher.Bind("tcp://127.0.0.1:9092")

    subscriber, _ := zmq4.NewSocket(zmq4.SUB)
    subscriber.SetLinger(0)
    defer subscriber.Close()

    subscriber.Connect("tcp://127.0.0.1:9092")
    subscriber.SetSubscribe("")

    go Listen(subscriber)
    for _ = range time.Tick(time.Second) {
        publisher.Send("test", 0)
        log.Println("send", "test")
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM