1

I have a ZeroMQ PUB/SUB connection between a server and clients written in Python. The server sends a message and the client prints it out.

These programs work perfectly fine in the same computer ( either Ubuntu 16.04, or Windows 7; both work ).

They also work when the server is on the Windows 7 machine and the client is on the Ubuntu 16.04 machine.

However, if the server is on the Ubuntu 16.04 machine then the client on the Windows 7 machine cannot connect to it.

Also, there is not a problem of communication when I move the client and server programs between two separate Windows 7 machines.

Does anyone know what the problem might be?

Here is the client code:

#Based on code found on this Stack Overflow post:
#https://stackoverflow.com/questions/43817161/how-to-send-opencv-video-footage-over-zeromq-sockets

import cv2
import zmq
import base64
import numpy as np

context = zmq.Context()
footage_socket = context.socket(zmq.SUB)
address = 'tcp://192.168.128.229:5555'
footage_socket.connect(address)
footage_socket.setsockopt_string(zmq.SUBSCRIBE, unicode(''))

print "start"
print "connecting to ", address

while True:
    try:
        frame = footage_socket.recv_string()
        img = base64.b64decode(frame)
        npimg = np.fromstring(img, dtype=np.uint8)
        source = cv2.imdecode(npimg, 1)
        cv2.imshow("image", source)
        cv2.waitKey(1)

    except KeyboardInterrupt:
        cv2.destroyAllWindows()
        print "\n\nBye bye\n"
        break

Here is the server code:

#Based on code found on this Stack Overflow post:
#https://stackoverflow.com/questions/43817161/how-to-send-opencv-video-footage-over-zeromq-sockets

import cv2
import zmq
import base64

context = zmq.Context()
footage_socket = context.socket(zmq.PUB)
footage_socket.bind('tcp://*:5555')
footage_socket.setsockopt(zmq.CONFLATE, 1)

camera = cv2.VideoCapture(0)

while True:
    try:
        (grabbed, frame) = camera.read()
        frame = cv2.resize(frame, (640, 480))
        encoded, buffer = cv2.imencode('.png', frame)
        footage_socket.send_string(base64.b64encode(buffer))


    except KeyboardInterrupt:
        camera.release()
        cv2.destroyAllWindows()
        print "\n\nBye bye\n"
        break
user3666197
  • 1
  • 6
  • 50
  • 92
Paul McElroy
  • 373
  • 1
  • 2
  • 13

1 Answers1

1

A list of Best Practices:

  • Interpretation: do not rely on re-dressing into a string-wrapped original content ( has made a lot issues once string became a byte in post Python-3.0+ )
  • Version control: not all versions of ZeroMQ core-facilities have the same modus-operandi ( PUB/SUB topic filtering happens on PUB side in recent versions, whereas was operated on SUB side, in the ZeroMQ earlier days. Versions do matter.
  • Performance: avoid as much overhead "external" to the core-flow of data as possible. Using base64.{b64encode()|b64decode()} is an example of such an adverse performance comfort, without delivering any adequate benefit.

  • Profile, tune and check the real costs of any cv2-based frame processing ~ colour-space conversions may take +170 [ms] p.i. ( in lower-left window )

  • May add any further details in a very cheap fashion right into aMessagePAYLOAD ( via struct.pack( aPayloadMASK, .data, OptionA, OptionB, OptionC ) - be it a rotating aSeqNumUINT8, aUsecTimeSTAMP, or whatever else one may like to add )

enter image description here

Do-s PUB-side:

import numpy as np
import zmq
import cv2
import struct

print( "INF: this process uses {0: >10s} v.{1:}".format(  "ZMQ",  zmq.__version__ ) )
print( "INF: this process uses {0: >10s} v.{1:}".format(  "NUMPY", np.__version__ ) )
...
..
aPubSOCKET.setsockopt( zmq.LINGER,        0 )
aPubSOCKET.setsockopt( zmq.IMMEDIATE,     1 )
aPubSOCKET.setsockopt( zmq.TOS,           aTypeOfSERVICE_PREFERENCE_ID )
aPubSOCKET.setsockopt( zmq.SNDHWM,        4 )
aPubSOCKET.setsockopt( zmq.SNDBUF,        4*640*480*3 )
aPubSOCKET.setsockopt( zmq.CONFLATE,      1 )
...
..
.
aPayloadMAP = ">"+ ( 640 * 480 * 3 )*"B"
HiResCAM    = cv2.VideoCapture( 0 )

while True:
      try:
          ( _ , cv2HiResFRAME ) = HiResCAM.read()    # acquire FRAME
          aPubSOCKET.send( struct.pack( aPayloadMAP, # pack to aMsgPAYLOAD, once .resize()'d
                                        cv2.resize( cv2HiResFRAME,
                                                    ( 640, 480 )
                                                    ).data
                                        ),           # OpenCV 2.2+ natively uses numpy arrays W * H * D * unit8 in BGR-ordering ( BGRA, if alpha used )
                           zmq.NOBLOCK
                           )

      except KeyboardInterrupt:
            # ...

      finally:
            # gracefully terminate all OpenCV resources
            # gracefully terminate all ZeroMQ resources
            break

Do-s SUB-side:

import numpy as np
import zmq
import cv2
import struct

print( "INF: this process uses {0: >10s} v.{1:}".format(  "ZMQ",  zmq.__version__ ) )
print( "INF: this process uses {0: >10s} v.{1:}".format(  "NUMPY", np.__version__ ) )
...
..
aSubSOCKET.setsockopt( zmq.LINGER,        0 )
aSubSOCKET.setsockopt( zmq.CONFLATE,      1 )
aSubSOCKET.setsockopt( zmq.MAXMSGSIZE,  100+640*480*3 )
aSubSOCKET.setsockopt( zmq.RCVHWM,        4 )
aSubSOCKET.setsockopt( zmq.RCVBUF,        4*640*480*3 )

aSubSOCKET.connect(                       address )
aSubSOCKET.setsockopt( zmq.SUBSCRIBE,    "" )

aPayloadMASK = ">" + ( 640 * 480 * 3 * "B" )

while True:
      try:
            cv2.imshow( "LAST IMAGERY AVAILABLE:",  struct.decode( aPayloadMASK, aSubSOCKET.recv() )
            cv2.waitKey( 1 )

      except KeyboardInterrupt:
            # ...

      finally:
            # gracefully terminate all OpenCV resources
            # gracefully terminate all ZeroMQ resources
            break
user3666197
  • 1
  • 6
  • 50
  • 92
  • Thank you. You mean by " is an example of such an adverse performance comfort," that this will degrade performance please? – Avv Oct 09 '22 at 16:50