day11-rabbitmq
RabbitMQ:消息队列,用于独立程序通信
依赖语言:erlang

一、简单通信
1 # --------------------------------------------- 2 # send端(producer) 3 # 建立socket->声明管道->声明queue->通过一个exchange发送内容至queue->关闭连接 4 # --------------------------------------------- 5 6 import pika 7 # 通过这个实例先建立一个socket 8 # rabbitmq默认端口15672,在python中使用pika模块 9 # 所有的socket 传输都是bytes类型 10 connection = pika.BlockingConnection(pika.ConnectionParameters("localhost")) 11 # 声明一个管道 12 channel = connection.channel() 13 # 声明queue, 名为test 14 # durable持久化队列,重启rabbitmq服务不会丢队列,但会丢消息,durable服务端和客户端都需写明 15 channel.queue_declare(queue="hello", durable=True) 16 # 发送 17 # 一个生产者对应多个消费者是采用轮询机制,公平的依次发给每一个消费者,每个消费者消费1个 18 # 假如一个生产者对应3个消费者,生产者发第一条消息,第一个消费者消费,生产者发第二条信息,第二个消费者消费... 19 channel.basic_publish(exchange="", 20 routing_key="hello", # queue的名字 21 body="hello world", # body是发送内容 22 properties=pika.BasicProperties(delivery_mode=2,), # 使消息持久化 23 ) 24 print("[x] Sent 'hello world'") 25 # 关闭连接 26 connection.close()
1 # --------------------------------------------- 2 # receive端(consumers) 3 # 创建socket连接->创建管道->声明queue->创建回调函数callback->消费的消息->开启消费 4 # --------------------------------------------- 5 6 7 import pika 8 # 使用byte格式 9 # 建立一个socket连接 10 # 消费者和生产者不一定在同一台机器上 11 connection = pika.BlockingConnection(pika.ConnectionParameters("localhost")) 12 # 创建一个管道 13 channel = connection.channel() 14 # 如果你确认queue已经存在可不写,但我们不确定是生产者还是消费者先运行,如果消费者先运行,此时这个queue不存在,会直接报错 15 # durable持久化,重启rabbitmq服务不会丢消息,durable服务端和客户端都需写明 16 channel.queue_declare(queue="test", durable=True) 17 18 19 def callback(ch, method, properites, body): 20 print("--->", ch, method, properites) 21 print(" [x] Received %r" % body) 22 # 手动确认消息已被消费 23 ch.basic_ack(delivery_tag=method.delivery_tag) 24 25 # 设置消费限额,设置为1则表示当前在处理的消息超过1条就不给此消费端发消息 26 channel.basic_qos(prefetch_count=1) 27 # 消费消息 28 channel.basic_consume( 29 callback, # 如果收到消息,就调用callback函数来处理消息 30 queue="test", # queue的名字 31 # no_ack=True, # 表示不关心消息是否处理完,一般情况不加,如果客户端没有确认,rabbitmq不会把消息删除 32 ) 33 print(' [*] Waiting for messages. To exit press CTRL+C') 34 35 # 这个start只要一启动,就一直运行,它不止收一条,而是永远收下去,没有消息就在这边卡住 36 # 正式开始收消息 37 channel.start_consuming()
二、广播模式
生产者:
import pika import sys connection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost')) channel = connection.channel() # --------------------------------------------------------------- # 1. fanout广播模式 # fanout广播模式,实时消息,如果没有消费端接收就消息就没了 channel.exchange_declare(exchange='logs', type='fanout') message = "info: Hello World!" # routing_key为空,广播模式不绑定队列 channel.basic_publish(exchange='logs', routing_key='', body=message) # ----------------------------------------------------------------- # 2.direct广播模式, 实时消息,有选择地接收消息,关键字发送 channel.exchange_declare(exchange='direct_logs', type='direct') severity = sys.argv[1] if len(sys.argv) > 1 else 'info' message = ' '.join(sys.argv[2:]) or 'Hello World!' channel.basic_publish(exchange='direct_logs', routing_key=severity, body=message) # ----------------------------------------------------------------- # 3.topic更细致的消息过滤 channel.exchange_declare(exchange='topic_logs', type='topic') routing_key = sys.argv[1] if len(sys.argv) > 1 else 'anonymous.info' message = ' '.join(sys.argv[2:]) or 'Hello World!' channel.basic_publish(exchange='topic_logs', routing_key=routing_key, body=message) # -------------------------------------------------------------------- print(" [x] Sent %r" % message) connection.close()
消费者:
1 import pika 2 import sys 3 4 connection = pika.BlockingConnection(pika.ConnectionParameters( 5 host='localhost')) 6 channel = connection.channel() 7 8 # --------------------------------------------------------------- 9 # 1. fanout广播模式 10 channel.exchange_declare(exchange='logs', 11 type='fanout') 12 13 # 生成一个随机的queue 14 # 不指定queue名字,rabbit会随机分配一个名字,exclusive=True会在使用此queue的消费者断开后,自动将queue删除 15 result = channel.queue_declare(exclusive=True) 16 queue_name = result.method.queue 17 18 # 队列绑定转发器,消费者只会从队列里拿消息 19 channel.queue_bind(exchange='logs', 20 queue=queue_name) 21 22 # ----------------------------------------------------------------- 23 # 2.direct广播模式 24 25 channel.exchange_declare(exchange='direct_logs', 26 type='direct') 27 28 result = channel.queue_declare(exclusive=True) 29 queue_name = result.method.queue 30 31 # 接收消息类型 32 severities = sys.argv[1:] 33 if not severities: 34 sys.stderr.write("Usage: %s [info] [warning] [error]\n" % sys.argv[0]) 35 sys.exit(1) 36 37 # 遍历绑定 38 for severity in severities: 39 channel.queue_bind(exchange='direct_logs', 40 queue=queue_name, 41 routing_key=severity) 42 43 # ----------------------------------------------------------------- 44 # 3.topic更细致的消息过滤 45 # 接收所有消息# 46 # 接收以mysql开头的消息: mysql.* 47 # 接收以info结尾的消息: *.info 48 channel.exchange_declare(exchange='topic_logs', 49 type='topic') 50 51 result = channel.queue_declare(exclusive=True) 52 queue_name = result.method.queue 53 54 # 接收消息内容 55 binding_keys = sys.argv[1:] 56 if not binding_keys: 57 sys.stderr.write("Usage: %s [binding_key]...\n" % sys.argv[0]) 58 sys.exit(1) 59 60 for binding_key in binding_keys: 61 channel.queue_bind(exchange='topic_logs', 62 queue=queue_name, 63 routing_key=binding_key) 64 65 # ----------------------------------------------------------------- 66 print(' [*] Waiting for logs. To exit press CTRL+C') 67 68 69 def callback(ch, method, properties, body): 70 print(" [x] %r" % body) 71 72 channel.basic_consume(callback, 73 queue=queue_name, 74 no_ack=True) 75 76 channel.start_consuming()
三、RPC=>remote procedure call

Client端:
1 import pika,uuid,time 2 3 class FibonacciRpcClient(object): 4 "斐波那契数列rpc客户端" 5 6 def __init__(self): 7 self.connection = pika.BlockingConnection(pika.ConnectionParameters 8 (host="localhost")) 9 self.channel = self.connection.channel() 10 result = self.channel.queue_declare(exclusive=True) 11 self.callback_queue = result.method.queue 12 self.channel.basic_consume(self.on_response,no_ack=True, 13 queue=self.callback_queue) 14 15 def on_response(self, ch, method, props, body): 16 print("---->", method, props) 17 if self.corr_id == props.correlation_id: # 我发过去的结果就是我想要的结果,保持数据的一致性 18 self.response = body 19 20 21 def call(self,n): 22 self.response = None 23 self.corr_id = str(uuid.uuid4()) 24 self.channel.publish(exchange="", 25 routing_key="rpc_queue", 26 properties=pika.BasicProperties( 27 reply_to=self.callback_queue, 28 correlation_id=self.corr_id), 29 body=str(n)) 30 while self.response is None: 31 self.connection.process_data_events() # 非阻塞版的start_consumer() 32 print("no msg....") 33 time.sleep(0.5) 34 return int(self.response) 35 36 if __name__ == "__main__": 37 fibonacci_rpc = FibonacciRpcClient() 38 print(" [x] Requesting fib(30)") 39 response = fibonacci_rpc.call(30) 40 print(" [.] Got %r" % response)
Server端:
1 import pika 2 import time 3 connection = pika.BlockingConnection(pika.ConnectionParameters( 4 host='localhost')) 5 6 channel = connection.channel() 7 8 channel.queue_declare(queue='rpc_queue') 9 10 def fib(n): 11 if n == 0: 12 return 0 13 elif n == 1: 14 return 1 15 else: 16 return fib(n-1) + fib(n-2) 17 18 def on_request(ch, method, props, body): 19 n = int(body) 20 21 print(" [.] fib(%s)" % n) 22 response = fib(n) 23 24 ch.basic_publish(exchange='', 25 routing_key=props.reply_to, 26 properties=pika.BasicProperties(correlation_id = \ 27 props.correlation_id), 28 body=str(response)) 29 ch.basic_ack(delivery_tag = method.delivery_tag) 30 31 channel.basic_qos(prefetch_count=1) 32 channel.basic_consume(on_request, queue='rpc_queue') 33 34 print(" [x] Awaiting RPC requests") 35 channel.start_consuming()

浙公网安备 33010602011771号