使用 ZeroMQ 消息库在 C 和 Python 间共享数据( 三 )

用如下命令编译:
$ clang -std=c99 -I. hw_interface.c -lzmq -o hw_interface如果没有编译错误,你就可以运行这个接口了 。贴心的是,ZeroMQ PUB 套接字可以在没有任何应用发送或接受数据的状态下运行,这简化了使用复杂度,因为这样不限制进程启动的次序 。
运行该接口:
$ ./hw_interfaceTopic: fancyhw_data; topic size: 12; Envelope size: 45Read 16 data valuesMessage sent; i: 0, topic: fancyhw_dataRead 16 data valuesMessage sent; i: 1, topic: fancyhw_dataRead 16 data values......输出显示数据已经通过 ZeroMQ 完成发送,现在要做的是让一个程序去读数据 。
编写 Python 数据处理器现在已经准备好从 C 程序向 Python 应用传送数据了 。

需要两个库帮助实现数据传输 。首先是 ZeroMQ 的 Python 封装:
$ python3 -m pip install zmq另一个就是 struct 库,用于解码二进制数据 。这个库是 Python 标准库的一部分,所以不需要使用 pip 命令安装 。
Python 程序的第一部分是导入这些库:
import zmqimport struct重要参数
使用 ZeroMQ 时,只能向常量 TOPIC 定义相同的接收端发送消息:
topic = "fancyhw_data".encode('ascii')print("Reading messages with topic: {}".format(topic))初始化
下一步,初始化上下文和套接字 。使用 subscribe 套接字(也称为 SUB 套接字),它是 PUB 套接字的天生伴侣 。这个套接字发送时也需要匹配主题 。
with zmq.Context() as context:    socket = context.socket(zmq.SUB)    socket.connect("tcp://127.0.0.1:5555")    socket.setsockopt(zmq.SUBSCRIBE, topic)    i = 0    ...接收消息
启动一个无限循环,等待接收发送到 SUB 套接字的新消息 。这个循环会在你按下 Ctrl+C 组合键或者内部发生错误时终止:
    try:        while True:            ... # we will fill this in next    except KeyboardInterrupt:        socket.close()    except Exception as error:        print("ERROR: {}".format(error))        socket.close()这个循环等待 recv() 方法获取的新消息,然后将接收到的内容从第一个空格字符处分割开,从而得到主题:
binary_topic, data_buffer = socket.recv().split(b' ', 1)解码消息
Python 此时尚不知道主题是个字符串,使用标准 ASCII 编解码器进行解码:
topic = binary_topic.decode(encoding = 'ascii')print("Message {:d}:".format(i))print("ttopic: '{}'".format(topic))下一步就是使用 struct 库读取二进制数据,它可以将二进制数据段转换为明确的数值 。首先,计算数据包中数值的组数 。本例中使用的 16 个位的有符号整数对应的是 struct 格式字符 中的 h:
packet_size = len(data_buffer) // struct.calcsize("h")print("tpacket size: {:d}".format(packet_size))知道数据包中有多少组数据后,就可以通过构建一个包含数据组数和数据类型的字符串,来定义格式了(比如“16h”):
struct_format = "{:d}h".format(packet_size)将二进制数据串转换为可直接打印的一系列数字:
data = struct.unpack(struct_format, data_buffer)print("tdata: {}".format(data))完整 Python 代码
下面是 Python 实现的完整的接收端:
#! /usr/bin/env python3import zmqimport structtopic = "fancyhw_data".encode('ascii')print("Reading messages with topic: {}".format(topic))with zmq.Context() as context:    socket = context.socket(zmq.SUB)    socket.connect("tcp://127.0.0.1:5555")    socket.setsockopt(zmq.SUBSCRIBE, topic)    i = 0    try:        while True:            binary_topic, data_buffer = socket.recv().split(b' ', 1)            topic = binary_topic.decode(encoding = 'ascii')            print("Message {:d}:".format(i))            print("ttopic: '{}'".format(topic))            packet_size = len(data_buffer) // struct.calcsize("h")            print("tpacket size: {:d}".format(packet_size))            struct_format = "{:d}h".format(packet_size)            data = struct.unpack(struct_format, data_buffer)            print("tdata: {}".format(data))            i += 1    except KeyboardInterrupt:        socket.close()    except Exception as error:        print("ERROR: {}".format(error))        socket.close()


推荐阅读