Problem: I fail subscribing to my publisher implemented in swift as soon as the publisher has published its first message.
Goal: Publish a data stream over ZeroMQ from my swift app. Then connect and disconnect a few subscribers and get messages through.
Background: I use swift5 and SwiftyZeroMQ5 (I have tested SwiftyZeroMQ too), I deploy on iPhone. I try to subscribe from both swift and python3. It only works if I connect my subscriber prior to publishing the first message. It also works if I first connect my subscriber then start the publisher app, then publishes. Corresponding publish and subscribe code on python3 does not require launching in any specific order and represents the behaviour I want. Since I get the sub/pub to work if I start i specific order, I know that IP-numbers, ports and topic, formatting etc are correct. Note that the behaviour is the same when I subscribe from both python3 and swift - it is not compatibility issues between swift and python.
Error messages: No error messages, the poller simply does not trigger if the processes are not started in the described order. The poller do trigger and messages and received if the processes are started in the described order.
What I tried: I've tried different combinations of publishers and subscribers regarding code base and devices.
- Swift pub to swift sub on same device [only works in described order]
- Swift pub to swift sub on different devices [only works in described order]
- Swift pub to python3 sub [only works in described order]
- Python3 pub to swift sub [works independent of start order]
- Python3 pub to python3 sub [works independent of start order]
My conclusion: There is a problem in the swift publisher socket: it fails to recognise new subscribers after it has published its first message.
Swift code for publisher, initPublisher is called in viewDidLoad(). ZeroMQ library version is 4.2.2:
import SwiftyZeroMQ5
var context: SwiftyZeroMQ.Context = try! SwiftyZeroMQ.Context()
var gpsPublisher: SwiftyZeroMQ.Socket?
let gpsPublishEndPoint = "tcp://*:5560"
// Init the publisher socket
func initPublisher()->Bool{
do{
self.gpsPublisher = try context.socket(.publish)
try self.gpsPublisher?.setSendBufferSize(4096)
try self.gpsPublisher?.setLinger(0) // Dont buffer messages
try self.gpsPublisher?.bind(self.gpsPublishEndPoint)
return true
}
catch{
print("Publish setup failed!")
return false
}
}
// ZMQ publish. Publishes string and serialized json-object
func publish(socket: SwiftyZeroMQ.Socket?, topic: String, json: JSON)->Bool{
// Create string with topic and json representation
let publishStr = getJsonStringAndTopic(topic: topic, json: json)
do{
try socket?.send(string: publishStr)
print("publish: Published: " + publishStr)
return true
}
catch{
print("publish: Error, tried to publish, but failed: " + publishStr)
return false
}
}
//The function is repeatedly called in a thread. Only function call shown here below.
_ = self.publish(socket: self.gpsPublisher, topic: "myTopic", json: json)
The python3 subscriber code, zmq.zmq_version() -> '4.3.2':
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect("tcp://192.168.1.2:5560")
socket.setsockopt_string(zmq.SUBSCRIBE, 'myTopic')
socket.RCVTIMEO = 1000 # in milliseconds
while socket:
try:
msg = str(socket.recv(), 'utf-8')
(topic, msg) = auxiliaries.zmq.demogrify(msg)
_print((topic, msg))
except zmq.error.Again as error:
_print(str(error))
except KeyboardInterrupt:
auxiliaries.zmq.close_socket_gracefully(socket)
socket = None
Any help, interesting test setups etc is very much appreciated.