【Rabbit MQ】数据源模拟程序【python3】【指定频率】【多线程】【pika】

Backgroud

该程序是用python3开发的,基于pika【pika是AMQP协议client端的一个python实现。其他的client端的python库还有如kombu,py-amqplib等】。
发送的数据是程序内模拟产生的各类传感器监测数据,具体数据格式下面详细介绍。数据发送可以指定发送频率,【最高支持毫秒级】,不支持微秒等更高频率的,还可以配置传感器的数量。
需要注意,配置的频率越高、传感器的个数越多,数据发送频率误差越大,目前我使用的配置是300个位移传感器,频率是20HZ,200个位移传感器,频率是10HZ。

发送消息格式

模拟产生的数据是逗号分隔的字符串,例如:100,20201015170020100,1,14,1,2,3,1,-7.182,-6.868,2.397,23,-9.077,5.666,-6.547
其中加粗斜体1,23这两个代表测点编号,后面跟的三个浮点数是三个指标对应的数值。
前7位代表的含义如下所示

序号 缩写 含义
1 pid 项目id
2 time 时间(17位字符串)(例子:20201015170020100)
3 funCode 功能码
4 targetType 测点类型
5 reserve 预留字节
6 targetAmount 测定个数
7 quotaAmount 指标个数

程序源码

# coding: utf-8
# import json
import _thread
import datetime
import random
import threading
import time

import pika


class RabbitMQUtil(object):
    """
    构造方法:
    config = {
        'host': '192.168.16.156',
        'port': 5672,
        'vHost': 'wlf',
        'username': 'wlf',
        'password': '123456',
        'exchange': 'sensorPayload_test',
        'routingKey': 'payload'
        }
    """

    # 初始化配置
    def __init__(self, conf):
        super().__init__()
        self.host = conf['host']
        self.port = conf['port']
        self.vHost = conf['vHost']
        self.username = conf['username']
        self.password = conf['password']
        self.exchange = conf['exchange']
        self.routingKey = conf['routingKey']
        self.credential = None
        self.connection = None
        self.channel = None

        try:
            self.credential = pika.PlainCredentials(self.username, self.password)
            self.connection = pika.BlockingConnection(
                pika.ConnectionParameters(self.host, self.port, self.vHost, self.credential))
            self.channel = self.connection.channel()
        except():
            print("connect error, please check the config")

    # 发布消息
    def publicMsg(self, json):
        # body = json.dumps({"test": "test"})
        self.channel.basic_publish(exchange=self.exchange, routing_key=self.routingKey, body=json)

    # 接收处理消息的回调函数
    def callback(self, channel, method, properties, body):
        super()
        # channel.basic_ack(delivery_tag=method.delivery_tag)
        print(str(body).replace('b', '').replace('\'', ''))

    # 订阅消息
    def consumeMsg(self, queue):
        self.channel.queue_declare(queue=queue, durable=True, arguments={
    
    "x-message-ttl": 259200000})
        self.channel.basic_consume(queue, self.callback, True)
        self.channel.start_consuming()

    # 关闭连接
    def close(self):
        if not self.connection:
            self.connection.close()
        else:
            print("connection already disconnected")


class MsgUtil(object):
    """
    构造方法:
    config = {
        'projectId': '100',
        'targetType': '1',
        'targetAmount': 300,
        'startSerialCode': 1,
        'quotaAmount': 6,
        'minValue': 1,
        'maxValue': 10
        }
    """

    def __init__(self, conf):
        self.projectId = conf['projectId']
        self.targetType = conf['targetType']
        self.targetAmount = conf['targetAmount']
        self.startSerialCode = conf['startSerialCode']
        self.quotaAmount = conf['quotaAmount']
        self.minValue = conf['minValue']
        self.maxValue = conf['maxValue']
        self.funCode = '1'
        self.reserve = '1'
        self.timestamp = None

    # 获取逗号分隔的字符串(项目id,时间(17位字符串),功能码,测点类型,预留字节,测定个数,指标个数,测点1id,指标1数值,指标2数值,...,测点2id,指标1数值,指标2数值,...,)
    # 例子:100,20201015170020100,1,14,1,2,3,1,-7.182,-6.868,2.397,23,-9.077,5.666,-6.547
    def get_msg(self):
        self.timestamp = get_format_time()
        base_info_seq = (self.projectId, str(self.timestamp), self.funCode, self.targetType, self.reserve,
                         str(self.targetAmount), str(self.quotaAmount))
        val_seq = ()
        for serialCode in range(self.startSerialCode, self.startSerialCode + self.targetAmount):
            val_seq = val_seq + (str(serialCode),)
            for i in range(1, self.quotaAmount + 1):
                random_value = get_random_value(serialCode, self.minValue, self.maxValue)
                val_seq = val_seq + (random_value,)

        return get_comma_str(base_info_seq, val_seq)


# 自定义线程类,指定频率向 RabbitMQ 发送消息
class myThread(threading.Thread):
    def __init__(self, thread_id, interval, msg_util):
        threading.Thread.__init__(self)
        self.thread_id = thread_id
        self.interval = interval
        self.msg_util = msg_util

    def run(self):
        conn = get_rabbit_connection()
        lastTime = 0
        while True:
            message = self.msg_util.get_msg()
            thisTime = get_milli_now()
            diffTime = thisTime - lastTime
            if diffTime < self.interval:
                delay = (self.interval - diffTime) / 1000
                time.sleep(delay)
            # 发布消息
            print(message)
            conn.publicMsg(message)
            lastTime = get_milli_now()


# 获取获逗号分隔的字符串,参数是元素为字符串的 tuple
def get_comma_str(*params):
    comma = ','
    res = ()
    for p in params:
        res = res + p
    return comma.join(res)


# 获取获取指定范围的一个随机数(字符串类型),保留三位小数
def get_random_value(n, minValue, maxValue):
    # 偶数全为正数
    if n % 2 == 0:
        return str(round(random.uniform(minValue, maxValue), 3))
    # 奇数有负数
    else:
        return str(round(random.uniform(maxValue * -1, maxValue), 3))


# 获取当前时间,格式:20200929173338500
def get_format_time():
    now = datetime.datetime.now()
    return now.strftime("%Y%m%d%H%M%S%f")[:-3]


# 指定频率向RabbitMQ发送消息
def produce_msg(*msg_conf):
    # param_list [interval1, msg_util1, interval2, msg_util2, ...]
    param_list = []
    for conf in msg_conf:
        frequency = conf['frequency']
        msg_util = MsgUtil(conf)
        # 发送时间间隔(ms)
        interval = 1000 / frequency
        param_list.append(interval)
        param_list.append(msg_util)
    send_msg(param_list)


# 多线程执行指定频率向RabbitMQ发送消息
def send_msg(param_list):
    intervals = param_list[::2]
    msg_utils = param_list[1::2]
    thread_list = []
    for i in range(len(intervals)):
        # 把毫秒转成微秒
        interval = intervals[i]
        msg_util = msg_utils[i]
        msg_util.get_msg()
        thread = myThread(i, interval, msg_util)
        thread_list.append(thread)
    # 先把所有线程启动
    for thread in thread_list:
        thread.start()
    # 然后再加入主线程中运行
    for thread in thread_list:
        thread.join()


# 获取 RabbitMQ 连接
def get_rabbit_connection():
    # 定义 RabbitMQ 配置参数
    rmq_config = {
    
    
        'host': 'elephant',
        'port': 5672,
        'vHost': 'wlf',
        'username': 'wlf',
        'password': '123456',
        'exchange': 'sensorPayload_test',
        'routingKey': 'payload'
    }
    return RabbitMQUtil(rmq_config)


# 获取13位当前毫秒时间戳,格式:1602747077320
def get_milli_now():
    return round(datetime.datetime.now().timestamp() * 1000)


if __name__ == '__main__':
    # 定义发布消息的基本信息
    msg_conf_1 = {
    
    
        'projectId': '100',
        'targetType': '1',
        'targetAmount': 300,
        'startSerialCode': 1,
        'quotaAmount': 6,
        'minValue': 1,
        'maxValue': 10,
        'frequency': 20
    }
    msg_conf_2 = {
    
    
        'projectId': '100',
        'targetType': '14',
        'targetAmount': 200,
        'startSerialCode': 501,
        'quotaAmount': 5,
        'minValue': 1,
        'maxValue': 6,
        'frequency': 10
    }

    produce_msg(msg_conf_1, msg_conf_2)

  • 打印信息如下图所示:
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_42761569/article/details/109101563
今日推荐