你好,世界
介紹
RabbitMQ是消息代理: 它接收並轉發信息。舉個例子: 小明從淘寶買了商品,配送員將快遞投遞到了快遞櫃, 小明再根據取件碼去快遞櫃取快遞。快遞櫃就相當於消息隊列,快遞員是生產者,小明是消費者。
-
生產者意味着發送, 所以發送信息的程序是生產者(Producer)。
-
儘管消息流經RabbitMQ和您的應用程序之中,但它們只能存儲在隊列之中, 甲隊列僅由主機的存儲器和磁盤限制和約束, 它本質上是一個大的消息緩衝器。許多生產者可以發送消息到同一個隊列中,許多消費者可以嘗試從一個隊列中接收數據, 表示隊列的方式。
-
消費與接收有相似的含義。消費者是一個程序,主要是等待接收信息。
生產者,消費者,消息隊列不必位於同一主機上。一個應用程序既可以是消費者,也可以是生產者。
你好, 世界!
本部分內容中, 使用python編寫兩個小程序, 分別實現生產者和消費者。生產者進行數據發送,消費者進行數據接收並將其打印出來。
如圖, P是生產者, 紅色矩形相等於消息隊列, C是消費者。 生產者將hello
發送到隊列中, 消費者從隊列中接收hello
。
RabbitMQ庫
RabbitMQ使用多種協議。本教程使用AMQP 0-9-1,這是一種開放的通用消息傳遞協議。RabbitMQ有許多不同語言的客戶。在本教程系列中,我們將使用Pika 1.0.0,這是RabbitMQ團隊推薦的Python客戶端。要安裝它,您可以使用 pip包管理工具安裝:
python -m pip install pika --upgrade
發送
- 我們第一個程序
send.py
需要向隊列發送一條消息。需要做的第一件事是與RabbitMQ服務器建立連接。前提你已經安裝了RabbitMQ
, 如果沒有安裝的話,可以參考我這篇博客使用Docker安裝RabbitMQ。
from pika import BlockingConnection, ConnectionParameters
# RabbitMQ連接參數,基本有默認值
parameters = ConnectionParameters(
host='localhost',
# port=_DEFAULT,
# virtual_host=_DEFAULT,
# credentials=_DEFAULT,
# channel_max=_DEFAULT,
# frame_max=_DEFAULT,
# heartbeat=_DEFAULT,
# ssl_options=_DEFAULT,
# connection_attempts=_DEFAULT,
# retry_delay=_DEFAULT,
# socket_timeout=_DEFAULT,
# stack_timeout=_DEFAULT,
# locale=_DEFAULT,
# blocked_connection_timeout=_DEFAULT,
# client_properties=_DEFAULT,
# tcp_options=_DEFAULT,
)
connection = BlockingConnection(parameters=parameters)
channel = connection.channel()
-
接下來, 在發送之前, 我們需要確保收件人隊列存在, 如果將消息發送到不存在的位置,RabbitMQ只會刪除該消息。創建一個
hello
隊列來信息消息傳遞:channel.queue_declare(queue='hello')
-
至此,準備發送消息了。第一個消息將字符串
Hello World!
發送到hello
隊列中。在RabbitMQ中, 永遠無法將消息直接發送到隊列, 它始終需要進行交換,可以在本教程的發佈/訂閱部分中閱讀相關信息。現在我們需要知道如何使用空字符串表示默認交換, 這種特殊的交換使我們可以準確的指定將信息發送到哪個隊列。隊列名稱需要在
routing_key
參數中指定:channel.basic_publish(exchange='', routing_key='hello', body='Hello World!') print('已發送: Hello World!')
-
通過關閉連接來刷新網絡緩存區:
connection.close()
接收
-
第二個程序
receive.py
將接收來自隊列的消息並將其打印出來。 -
同樣需要先連接
RabbitMQ
服務器, 負責連接RabbitMQ
的代碼與之前代碼相同。 -
像
send.py
一樣,需要確保隊列是否存在, 使用queue_declare
創建隊列是冪等的, 可以根據需要多次使用該命令, 但是隻會創建一個。channel.queue_declare(queue='hello')
在
send.py
中已經聲明瞭該隊列且已經運行,這裏其實可以不用聲明,但是考慮到不確定哪個程序先執行, 所以最好在兩個程序中重複聲明。 -
查看消息隊列中有多少消息,
linux
下可以通過:rabbitmqctl list_queues
命令查看,windows通過rabbitmqctl.bat list_queues
查看。如果安裝了web
控制檯,登錄之後可以切換到Queues
標籤下查看。 -
接收消息比發生消息複雜一點, 通過回調函數來進行操作,當隊列收到消息時會回調我們制定的消息處理函數。
def callback(ch, method, properties, body): """ :param ch: :param method: :param properties: :param body: :return: """ print("收到消息: {}".format(body))
-
接下來, 需要告訴隊列指定回調函數和從哪個隊列接收消息。
channel.basic_consume(queue='hello',
auto_ack=True,
on_message_callback=callback)
-
最後進入一個無限循環, 該循環等待數據並在必要的時候進行回調。
print('等待接收消息, 按CTRL+C退出....') channel.start_consuming()
代碼整合
send.py
from pika import BlockingConnection, ConnectionParameters
# RabbitMQ連接參數,基本有默認值
parameters = ConnectionParameters(
host='localhost',
# port=_DEFAULT,
# virtual_host=_DEFAULT,
# credentials=_DEFAULT,
# channel_max=_DEFAULT,
# frame_max=_DEFAULT,
# heartbeat=_DEFAULT,
# ssl_options=_DEFAULT,
# connection_attempts=_DEFAULT,
# retry_delay=_DEFAULT,
# socket_timeout=_DEFAULT,
# stack_timeout=_DEFAULT,
# locale=_DEFAULT,
# blocked_connection_timeout=_DEFAULT,
# client_properties=_DEFAULT,
# tcp_options=_DEFAULT,
)
connection = BlockingConnection(parameters=parameters)
channel = connection.channel()
channel.queue_declare(queue='hello')
channel.basic_publish(exchange='',
routing_key='hello',
body='Hello World!')
print('已發送: Hello World!')
connection.close()
receive.py
from pika import BlockingConnection, ConnectionParameters
# RabbitMQ連接參數,基本有默認值
parameters = ConnectionParameters(
host='localhost',
# port=_DEFAULT,
# virtual_host=_DEFAULT,
# credentials=_DEFAULT,
# channel_max=_DEFAULT,
# frame_max=_DEFAULT,
# heartbeat=_DEFAULT,
# ssl_options=_DEFAULT,
# connection_attempts=_DEFAULT,
# retry_delay=_DEFAULT,
# socket_timeout=_DEFAULT,
# stack_timeout=_DEFAULT,
# locale=_DEFAULT,
# blocked_connection_timeout=_DEFAULT,
# client_properties=_DEFAULT,
# tcp_options=_DEFAULT,
)
connection = BlockingConnection(parameters=parameters)
channel = connection.channel()
channel.queue_declare(queue='hello')
def callback(ch, method, properties, body):
"""
:param ch:
:param method:
:param properties:
:param body:
:return:
"""
print("收到消息: {}".format(body))
channel.basic_consume(queue='hello',
auto_ack=True,
on_message_callback=callback)
print('等待接收消息, 按CTRL+C退出....')
channel.start_consuming()
-
先
python send.py
發送消息, 控制檯輸出:已發送: Hello World!
-
然後
python receive.py
, 發現控制檯永遠不會退出:等待接收消息, 按CTRL+C退出.... 收到消息: b'Hello World!'
-
再次
python send.py
, 會再次進行函調函數, 輸出b'Hello World!'
。
原文鏈接。