问题:在发布者发布第一条消息后,我未能立即订阅我的发布者。
目标:从我的 swift 应用程序通过 ZeroMQ 发布数据流。然后连接和断开一些订阅者并接收消息。
背景:我使用 swift5 和 SwiftyZeroMQ5(我也测试过 SwiftyZeroMQ),我部署在 iPhone 上。我尝试同时订阅 swift 和 python3。只有当我在发布第一条消息之前连接我的订阅者时,它才有效。如果我首先连接我的订阅者然后启动发布者应用程序,然后发布,它也可以工作。 python3上对应的发布和订阅代码不需要以任何特定的顺序启动,代表了我想要的行为。 因为如果我开始特定的订单,我就会让 sub/pub 工作,所以我知道 IP 号码、端口和主题、格式等都是正确的。 请注意,当我同时订阅 python3 和 swift 时,行为是相同的 - 这不是 swift 和 python 之间的兼容性问题。
错误消息:没有错误消息,如果进程没有按照描述的顺序启动,轮询器不会触发。如果进程按照描述的顺序启动,轮询器会触发并接收消息。
我尝试过的:我尝试了关于代码库和设备的不同发布者和订阅者组合。
我的结论: swift 发布者套接字存在一个问题:它在发布第一条消息后无法识别新订阅者。
发布者的Swift代码,在viewDidLoad()中调用initPublisher。 ZeroMQ 库版本为 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)
python3订阅者代码, 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
非常感谢任何帮助、有趣的测试设置等。
答案 0 :(得分:0)
我进行了更多测试,发现了一些问题和解决方法。
我制作了一个最小的工作示例应用程序,如果您愿意或需要深入挖掘,您可以使用它。它有“init”、“bind”、“publish”和“bind and publish”按钮。您可以发送一批消息并检查时间等。 我向 python3 脚本运行该应用程序。 我通过 cocoapods 包含了 SwiftyZeroMQ5。
Podfile:
platform :ios, '13.0'
target 'ZMQtest' do
use_frameworks!
pod 'SwiftyZeroMQ5'
end
SwiftCode(您自己设置按钮..)
import UIKit
import SwiftyZeroMQ5
class ViewController: UIViewController {
let context = try! SwiftyZeroMQ.Context()
var publisher: SwiftyZeroMQ.Socket?
let publishEndPoint = "tcp://*:5560"
var cnt = 0
let quota = 1200
@IBAction func publishButtonPressed(_ sender: Any) {
while cnt < quota {
publish()
//usleep(10000)
}
cnt = 1
}
@IBAction func bindAndPublishButtonPressed(_ sender: Any) {
while cnt < quota {
bindPublisher()
publish()
}
cnt = 1
}
@IBAction func initPubButtonPressed(_ sender: Any) {
initPublisher()
}
@IBAction func bindPublisherButtonPressed(_ sender: Any) {
bindPublisher()
}
@IBOutlet weak var statusLabel: UILabel!
// **************
// Init publisher
func initPublisher(){
do {
self.publisher = try context.socket(.publish)
print("Publisher socket created")
}
catch {
print("initPublisher error: ", error)
}
}
// **************
// Bind publisher
func bindPublisher(){
do {
try self.publisher?.bind(publishEndPoint)
print("Publisher socket binded to :", publishEndPoint)
}
catch {
print("bindPublisher error: ", error)
}
}
// *****************
// Publish a message
func publish(){
// Publish dummy string
do{
cnt += 1
let str = "topic {\"key\": \"" + String(cnt) + "\"}"
try self.publisher?.send(string: str)
statusLabel.text = str
print("Publish message no: ", String(cnt))
}
catch{
print("publisher error: ", error)
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
以及python3代码:
#!/usr/bin/env python3
'''Minimal running example of a ZMQ SUB socket.'''
import json
import zmq
def demogrify(msg: str):
'''inverse of mogrify()'''
try:
(topic, message) = msg.split(maxsplit=1)
except ValueError:
(topic, message) = (msg, '{}')
return topic, json.loads(message)
def close_socket_gracefully(socket):
'''graceful termination'''
socket.setsockopt(zmq.LINGER, 0) # to avoid hanging infinitely
socket.close()
if __name__ == "__main__":
context = zmq.Context()
socket = context.socket(zmq.SUB) #pylint: disable=no-member
socket.connect("tcp://192.168.1.2:5560")
socket.setsockopt_string(zmq.SUBSCRIBE, '') #pylint: disable=no-member
socket.RCVTIMEO = 1000 # in milliseconds
while socket:
try:
msg = str(socket.recv(), 'utf-8')
(topic, msg) = demogrify(msg)
print((topic, msg))
except zmq.error.Again as error:
print(str(error))
except KeyboardInterrupt:
close_socket_gracefully(socket)
socket = None
我是否应该将此问题标记为已解决?