RabbitMQ Python 入门教程之HelloWorld

你好,世界

介绍

RabbitMQ是消息代理: 它接收并转发信息。举个例子: 小明从淘宝买了商品,配送员将快递投递到了快递柜, 小明再根据取件码去快递柜取快递。快递柜就相当于消息队列,快递员是生产者,小明是消费者。

  • 生产者意味着发送, 所以发送信息的程序是生产者(Producer)。

    img

  • 尽管消息流经RabbitMQ和您的应用程序之中,但它们只能存储在队列之中, 甲队列仅由主机的存储器和磁盘限制和约束, 它本质上是一个大的消息缓冲器。许多生产者可以发送消息到同一个队列中,许多消费者可以尝试从一个队列中接收数据, 表示队列的方式。

    img

  • 消费与接收有相似的含义。消费者是一个程序,主要是等待接收信息。

    img

生产者,消费者,消息队列不必位于同一主机上。一个应用程序既可以是消费者,也可以是生产者。

你好, 世界!

本部分内容中, 使用python编写两个小程序, 分别实现生产者和消费者。生产者进行数据发送,消费者进行数据接收并将其打印出来。

如图, P是生产者, 红色矩形相等于消息队列, C是消费者。 生产者将hello 发送到队列中, 消费者从队列中接收hello

img

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()
    

接收

img

  • 第二个程序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!'

原文链接

发布了72 篇原创文章 · 获赞 147 · 访问量 35万+

猜你喜欢

转载自blog.csdn.net/ClassmateLin/article/details/104575857