Jak skonfigurować Multiple PUB / pojedynczy SUB python ZMQ Ubuntu

Nov 19 2020

Mam dwie maszyny wirtualne (VirtualBOx, Ubuntu 18.04 i python-zmq [16.0.2-2build2]) działające na tej samej maszynie fizycznej (Win10). Oba komputery są skonfigurowane jako most i mogą pomyślnie wysyłać pakiety ping pod adres 192.168.1.66-192.168.1.55. Skorzystałem z tego samouczkahttps://learning-0mq-with-pyzmq.readthedocs.io/en/latest/pyzmq/patterns/pubsub.html. Działa, jeśli PUB (serwer) jest skonfigurowany jako

import zmq
import random
import sys
import time

port = "5557"
if len(sys.argv) > 1:
    port =  sys.argv[1]
    int(port)

context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind("tcp://*:%s" % port)
while True:
    topic = random.randrange(9999,10005)
    messagedata = random.randrange(1,215) - 80
    print "%d %d" % (topic, messagedata)
    socket.send("%d %d" % (topic, messagedata))
    time.sleep(1)

A SUB (klient) jako

import sys
import zmq

port = "5557"
if len(sys.argv) > 1:
    port =  sys.argv[1]
    int(port)
    
if len(sys.argv) > 2:
    port1 =  sys.argv[2]
    int(port1)

# Socket to talk to server
context = zmq.Context()
socket = context.socket(zmq.SUB)

print "Collecting updates from weather server..."
socket.connect ("tcp://192.168.1.66:%s" % port)

if len(sys.argv) > 2:
    socket.connect ("tcp://localhost:%s" % port1)
# Subscribe to zipcode, default is NYC, 10001
topicfilter = "10001"
socket.setsockopt(zmq.SUBSCRIBE, topicfilter)

# Process 5 updates
total_value = 0
for update_nbr in range (5):
    string = socket.recv()
    topic, messagedata = string.split()
    total_value += int(messagedata)
    print topic, messagedata

print "Average messagedata value for topic '%s' was %dF" % (topicfilter, total_value / update_nbr)

Ponieważ chcę jednego klienta (SUB) z wieloma serwerami (PUB), na których mogą być setki, a nawet tysiące, skonfigurowanie jednego adresu IP dla każdego PUB jest niewykonalne. Czy istnieje sposób na subskrybowanie bez podawania adresu IP? Albo przynajmniej transmisję. Próbowałem skonfigurować u klienta w socket.connect ("tcp://IP:%s" % port):

„*”

Podaje błąd:

Traceback (most recent call last):
  File "sub_client.py", line 18, in <module>
    socket.connect ("tcp://*:%s" % port)
  File "zmq/backend/cython/socket.pyx", line 528, in zmq.backend.cython.socket.Socket.connect (zmq/backend/cython/socket.c:5980)
  File "zmq/backend/cython/checkrc.pxd", line 25, in zmq.backend.cython.checkrc._check_rc (zmq/backend/cython/socket.c:8400)
zmq.error.ZMQError: Invalid argument

192.168.1.1 (GW), 192.168.1.255 (broadcast), localhost / 127.0.0.1 i jego IP (192.168.1.55) -> nie odbiera wiadomości

192.168.1.66 (adres IP serwera) -> Odbiera wiadomości, ale nie jest praktyczny w systemie o dużej skali

Jakiś sposób, aby to rozwiązać?

Odpowiedzi

user3666197 Nov 19 2020 at 22:21

P : Jakiś sposób na rozwiązanie tego problemu?

Unikaj używania jakichkolwiek właściwości udokumentowanych przez API. Podczas gdy .bind()-method może dla tcp://-transport-class rzeczywiście próbować łączyć się z dowolnymi localhost-side adresami IP, to .connect()-method z oczywistych powodów nie może.

Jak podano w ZMQError:

socket.connect ("tcp://*:%s" % port)
zmq.error.ZMQError: Niepoprawny argument

Popraw docelowy adres IP, przy czym
.connect( "tcp://{0:}:{1:}".format( IP, PORT ) )-metoda powinna próbować „zadzwonić tak, aby uzyskać połączenie”.