1. MQTT 的主题模式
MQTT 的核心就是 发布 / 订阅主题:
- 客户端直接
PUBLISH到一个主题(例如sensor/temp)。 - 其他客户端
SUBSCRIBE同一个主题或通配符主题(例如sensor/#)。 - Broker 负责将消息推送给所有订阅了匹配主题的客户端。
- 主题是轻量级的字符串,支持层级(
/分隔)和通配符(+单层,#多层)。 - 不需要提前声明主题,客户端可以随时发布或订阅。
2. AMQP 的类似机制
AMQP 没有 "主题" 这个概念,但可以通过 交换机(Exchange)+ 队列(Queue)+ 绑定(Binding) 来模拟 MQTT 的主题效果:
1.使用 topic 类型交换机
-
交换机类型 :
topic -
路由键(Routing Key) :用点
.分隔,类似 MQTT 的主题层级,例如:plaintext
sensor.temp sensor.humidity device.control -
绑定键(Binding Key) :支持通配符:
*匹配一个单词(层级)#匹配零个或多个单词(层级)
例子:
- 生产者发送消息到交换机
my_topic_exchange,路由键sensor.temp。 - 队列 topic
_queue绑定到交换机,绑定键sensor.#→ 会收到所有sensor.xxx的消息。
3.交换机、队列和绑定关系的示意图

示意图说明
- 交换机 :
my_topic_exchange(类型topic) - 队列 :
topic_queue - 绑定键 :
sensor.#(只匹配以sensor开头的主题) - 生产者 发布不同主题的消息:
sensor.temp→ 消费者收到sensor.humidity→ 消费者收到device.control→ 消费者不会收到 (因为绑定键只匹配sensor开头的主题)
4.Python程序
setup_topic.py:负责初始化 RabbitMQ 的交换机、队列和绑定规则,是整个消息系统的基础。producer_topic.py:负责发送消息到交换机,每条消息可以指定不同的主题。consumer_topic.py:负责从队列中接收并处理消息,但只订阅特定主题(sensor开头)。
1. setup_topic.py
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
setup_topic.py - 一次性创建 RabbitMQ Topic 交换机、队列和绑定关系
功能说明:
1. 连接到 RabbitMQ Broker
2. 创建 topic 类型交换机(持久化)
3. 创建队列(持久化)
4. 将队列绑定到交换机,只接收 sensor 开头的主题
"""
import pika
# ======================== 配置参数 ========================
HOST = 'localhost' # RabbitMQ 服务器的 IP 地址
PORT = 5672 # RabbitMQ 默认 AMQP 端口
USER = 'mi_user' # 用户名
PASSWORD = 'YourPassword123' # 密码
EXCHANGE_NAME = 'my_topic_exchange' # 交换机名称
QUEUE_NAME = 'topic_queue' # 队列名称
BINDING_KEY = 'sensor.#' # 绑定键(只匹配 sensor 开头的主题)
try:
# 1. 创建连接(BlockingConnection 表示同步阻塞模式)
conn = pika.BlockingConnection(
pika.ConnectionParameters(
host=HOST,
port=PORT,
credentials=pika.PlainCredentials(USER, PASSWORD) # 用户名密码认证
)
)
# 2. 创建一个信道(Channel),所有操作都在信道中进行
ch = conn.channel()
print(f"✅ 连接成功 {HOST}:{PORT}")
# 3. 创建 topic 交换机
# exchange_type='topic':支持通配符的主题交换机
# durable=True:交换机持久化,RabbitMQ 重启后仍然存在
ch.exchange_declare(
exchange=EXCHANGE_NAME,
exchange_type='topic',
durable=True
)
print(f"✅ 交换机 '{EXCHANGE_NAME}' 已创建")
# 4. 创建队列
# durable=True:队列持久化,RabbitMQ 重启后仍然存在
ch.queue_declare(queue=QUEUE_NAME, durable=True)
print(f"✅ 队列 '{QUEUE_NAME}' 已创建")
# 5. 绑定队列到交换机
# routing_key=BINDING_KEY:绑定键(交换机根据绑定键过滤消息)
# 'sensor.#':匹配所有以 sensor 开头的主题(包括多层级)
ch.queue_bind(
exchange=EXCHANGE_NAME,
queue=QUEUE_NAME,
routing_key=BINDING_KEY
)
print(f"✅ 已绑定队列到交换机,绑定键: {BINDING_KEY}")
# 6. 关闭连接
conn.close()
print("\n✅ 基础设施配置完成!")
except Exception as e:
# 捕获并处理异常
print(f"❌ 配置失败: {e}")
2. producer_topic.py
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
producer_topic.py - 发布消息到不同的主题
功能说明:
1. 连接到 RabbitMQ Broker
2. 使用 topic 交换机发布消息
3. 支持不同主题(路由键)
"""
import pika
import json
# ======================== 配置参数 ========================
HOST = 'localhost' # RabbitMQ 服务器的 IP 地址
PORT = 5672 # RabbitMQ 默认 AMQP 端口
USER = 'mi_user' # 用户名
PASSWORD = 'YourPassword123' # 密码
EXCHANGE_NAME = 'my_topic_exchange' # 交换机名称
def send_to_topic(topic, message):
"""
发送消息到指定主题(路由键)
:param topic: 主题字符串,例如 "sensor.temp"
:param message: 消息内容(Python 字典)
"""
# 1. 创建连接
conn = pika.BlockingConnection(
pika.ConnectionParameters(
host=HOST,
port=PORT,
credentials=pika.PlainCredentials(USER, PASSWORD)
)
)
# 2. 创建信道
ch = conn.channel()
# 3. 声明 topic 交换机(确保存在)
ch.exchange_declare(
exchange=EXCHANGE_NAME,
exchange_type='topic',
durable=True
)
# 4. 发布消息到指定主题(路由键)
ch.basic_publish(
exchange=EXCHANGE_NAME,
routing_key=topic,
body=json.dumps(message),
properties=pika.BasicProperties(delivery_mode=2) # 持久化消息
)
print(f"✅ 发布到主题 [{topic}]: {message}")
conn.close()
if __name__ == "__main__":
# 模拟发布不同主题的消息
send_to_topic("sensor.temp", {"value": 25.5, "unit": "C"})
send_to_topic("sensor.humidity", {"value": 60, "unit": "%"})
send_to_topic("device.control", {"cmd": "restart", "target": "sensor_001"})
3. consumer_topic.py
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
consumer_topic.py - 只订阅 sensor 开头的主题
功能说明:
1. 连接到 RabbitMQ Broker
2. 绑定队列到 topic 交换机,只接收 sensor 开头的主题
3. 消费消息并手动确认
"""
import pika
import json
# ======================== 配置参数 ========================
HOST = 'localhost' # RabbitMQ 服务器的 IP 地址
PORT = 5672 # RabbitMQ 默认 AMQP 端口
USER = 'mi_user' # 用户名
PASSWORD = 'YourPassword123' # 密码
EXCHANGE_NAME = 'my_topic_exchange' # 交换机名称
QUEUE_NAME = 'topic_queue' # 队列名称
def callback(ch, method, properties, body):
"""
收到消息的回调函数
:param ch: 信道对象
:param method: 消息方法属性(包含 delivery_tag 等)
:param properties: 消息属性
:param body: 消息内容(二进制数据)
"""
topic = method.routing_key # 获取消息的主题(路由键)
message = json.loads(body.decode('utf-8')) # 将二进制数据转换为 Python 字典
print(f"\n📨 收到主题 [{topic}]: {message}")
ch.basic_ack(delivery_tag=method.delivery_tag) # 手动确认消息已处理完成
def start_consumer():
"""
启动消费者,只订阅 sensor 开头的主题
"""
# 1. 创建连接
conn = pika.BlockingConnection(
pika.ConnectionParameters(
host=HOST,
port=PORT,
credentials=pika.PlainCredentials(USER, PASSWORD)
)
)
# 2. 创建信道
ch = conn.channel()
# 3. 声明 topic 交换机(确保存在)
ch.exchange_declare(
exchange=EXCHANGE_NAME,
exchange_type='topic',
durable=True
)
# 4. 声明队列(确保存在)
ch.queue_declare(queue=QUEUE_NAME, durable=True)
# 5. 绑定队列到交换机,只接收 sensor 开头的主题
ch.queue_bind(
exchange=EXCHANGE_NAME,
queue=QUEUE_NAME,
routing_key='sensor.#' # 绑定键(只匹配 sensor 开头的主题)
)
# 6. 设置每次只处理一条消息(公平分发)
ch.basic_qos(prefetch_count=1)
# 7. 开始消费消息
ch.basic_consume(queue=QUEUE_NAME, on_message_callback=callback, auto_ack=False)
print(f"🔄 开始订阅 sensor 开头的主题 (按 Ctrl+C 退出)")
ch.start_consuming()
if __name__ == "__main__":
start_consumer()