RabbitMQ-C使用开发详解(Windows环境)

目录

一、概述

二、编译RabbitMQ-c

三、核心原理

3.1生产者与交换机关系

3.2交换机与队列关系

3.3队列与消费者关系

3.4交换机与交换机的关系

四、开发者

4.1接口文件

4.2交换机

声明交换机

删除交换机

向交换机绑定路由键

从交换机解绑路由键

交换机之间绑定路由键

交换机之间解绑路由键

4.3队列

声明队列

清空队列

删除队列

4.4生产者

4.5消费者

4.5.1订阅

4.5.2拉取


RabbitMQ-C使用开发详解(Windows环境)

 

一、概述

讨论的是windows环境下的使用RabbitMQ-c与RabbitMQ服务端的交互。

 

二、编译RabbitMQ-c

RabbitMq的C/C++客户端有很多,我们选用RabbitMq-c。windows环境下的MFC开发,需要把RabbitMq-c客户端编译成dll。

1.下载和安装

下载rabbitmq-c最新代码包:https://github.com/alanxz/rabbitmq-c

下载cmake最新安装包:https://cmake.org/download/

2.使用cmake编译生成适合自己编译环境的工程

第一步:填写源代码路径

第二步:填写建立后的路径,build的文件夹一般建立在源代码路径里,也可以放在其他位置

第三步:点击配置按钮,在配置里面选择属于自己编译环境的名字

第四步:点击生成按钮,不出现运行失败就说明已经编译成功了

     RabbitMQ-C使用开发详解(Windows环境)_第1张图片  

特别说明:在编译rabbitmq-c是如果出现如图的错误,可以去掉ENABLE_SSL_SUPPORT括号里的对勾。 

RabbitMQ-C使用开发详解(Windows环境)_第2张图片

 

在以上生成的工程目录下的librabbitmq\Debug路径下会生成librabbitmq.4.lib、librabbitmq.4.dll两个文件,对应的动态库的导出文件在rabbitmq-c-master\librabbitmq目录下。

 

三、核心原理

3.1生产者与交换机关系

生产者与交换机的关系是多对多的有关系,多个生产者可以给同一个交换机生产消息,同时一个生产者也可以能多个交换机生产消息。

 

3.2交换机与队列关系

交换机与队列的关系是多对多的关系,一个交换机可以给多个队列提供消息,同时多个交换机也可以同时给一个队列提供消息。

 

3.3队列与消费者关系

队列与消费者的关系是多对多的关系,一个队列可以同时被多个消费者消费,同时一个消费者可以同时消费多个队列的消息。

3.4交换机与交换机的关系

交换机与交换机的关系,与交换机与队列的关系是一样的。部份交换机充当队列的角色,从其绑定的交换机上分流数据,然后再把自己角色转换成交换机,然后给绑定在自身上的队列分派消息。

所以交换机之间的关系是多对多,一个上级交换机可以绑定多个下级交换机,一个下级交换机可同时绑定多个上级交换机。

四、开发者

4.1接口文件

总共有4个导出文件:

amqp.h:主要的rabbitmq-c客户端接口都在此文件

amqp_tcp_socket.h:与socket相关的接口

mqp_framing.h:不常用的一些接口

amqp_ssl_socket.h:用户ssl方式加密访问rabbitmq-server

 

生产者生产消息过程:

(1)客户端连接到消息队列服务器,打开一个channel。

(2)客户端声明一个exchange,并设置相关属性。

(3)客户端声明一个queue,并设置相关属性。

(4)客户端使用routing key,在exchange和queue之间建立好绑定关系。

(5)客户端投递消息到exchange。

 

RabbitMQ支持消息的持久化:

也就是数据写在磁盘上,为了数据安全考虑,我想大多数用户都会选择持久化。如果exchange和queue都是持久化的,那么它们之间的binding也是持久化的。如果exchange和queue两者之间有一个持久化,一个非持久化,就不允许建立绑定。消息队列持久化包括3个部分:

(1)exchange持久化,在声明时指定durable => 1

(2)queue持久化,在声明时指定durable => 1

(3)消息持久化,在投递时指定delivery_mode=> 2(1是非持久化)

4.2交换机

声明交换机

AMQP_PUBLIC_FUNCTION amqp_exchange_declare_ok_t *AMQP_CALL amqp_exchange_declare(amqp_connection_state_t state, amqp_channel_t channel,amqp_bytes_t exchange, amqp_bytes_t type, amqp_boolean_t passive,amqp_boolean_t durable, amqp_boolean_t auto_delete, amqp_boolean_t internal,amqp_table_t arguments);

 

/**

 * amqp_exchange_declare

 *

 * @param [in] connect连接 amqp_new_connection获取

 * @param [in] channel the channel to do the RPC on,程序自己设置一个通道号,一个连接可以多个通道号。

 * @param [in] exchange 指定交换机名称 eg:amqp_cstring_bytes("exchange_cat")

 * @param [in] type 指定交换机类型,amqp_cstring_bytes("direct") 

 * "fanout" 广播的方式,发送到该exchange的所有队列上。

 * "direct" 通过路由键发送到指定的队列上。

 * "topic" 通过匹配路由键的方式获取,使用通配符*,#

 * @param [in] passive 检测exchange是否存在,设为true,若exchange存在则命令成功返回(调用其他参数不会影响exchange属性),若不存在不会创建exchange,返回错误。设为false,如果exchange不存在则创建exchange,调用成功返回。如果exchange已经存在,并且匹配现在exchange的话则成功返回,如果不匹配则exchange声明失败。

 * @param [in] durable 队列是否持久化

 * @param [in] auto_delete 连接断开的时候,exchange是否自动删除

 * @param [in] internal internal

 * @param [in] arguments arguments

 * @returns amqp_exchange_declare_ok_t

 */

 

Demo示例:


#include 
#include 
void die_on_amqp_error2(amqp_rpc_reply_t x, char const *context) {
	char sLog[1024] = {0};
	switch (x.reply_type) {
	case AMQP_RESPONSE_NORMAL:
		return;

	case AMQP_RESPONSE_NONE:
		printf(sLog, "%s: missing RPC reply type!\n", context);
		break;

	case AMQP_RESPONSE_LIBRARY_EXCEPTION:
		printf(sLog, "%s: %s\n", context, amqp_error_string2(x.library_error));
		break;

	case AMQP_RESPONSE_SERVER_EXCEPTION:
		switch (x.reply.id) {
		case AMQP_CONNECTION_CLOSE_METHOD: {
			amqp_connection_close_t *m =
				(amqp_connection_close_t *)x.reply.decoded;
			printf(sLog, "%s: server connection error %uh, message: %.*s\n",
				context, m->reply_code, (int)m->reply_text.len,
				(char *)m->reply_text.bytes);
			break;
										   }
		case AMQP_CHANNEL_CLOSE_METHOD: {
			amqp_channel_close_t *m = (amqp_channel_close_t *)x.reply.decoded;
			printf(sLog, "%s: server channel error %uh, message: %.*s\n",
				context, m->reply_code, (int)m->reply_text.len,
				(char *)m->reply_text.bytes);
			break;
										}
		default:
			printf(sLog, "%s: unknown server error, method id 0x%08X\n",
				context, x.reply.id);
			break;
		}
		break;
	}

	AfxMessageBox(sLog);
}


void die_on_error2(int x, char const *context) {
	if (x < 0) {
		char sLog[1024] = {0};
		printf(sLog, "%s: %s\n", context, amqp_error_string2(x));
		AfxMessageBox(sLog);
	}
}

void Crabbitmq_demoDlg::OnBnClickedButton1()
{
	char const *hostname;
	int port, status;
	char const *exchange;
	char const *exchangetype;
	amqp_socket_t *socket = NULL;
	amqp_connection_state_t conn;

	hostname ="localhost";
	port = 5672;
	exchange = "test.fanout";
	exchangetype = "fanout"; //fanout/direct/topic

	conn = amqp_new_connection();

	socket = amqp_tcp_socket_new(conn);
	if (!socket) {
		AfxMessageBox("creating TCP socket");
	}

	status = amqp_socket_open(socket, hostname, port);
	if (status) {
		AfxMessageBox("opening TCP socket");
	}

	die_on_amqp_error2(amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN,
		"guest", "guest"),
		"Logging in");
	amqp_channel_open(conn, 1);
	die_on_amqp_error2(amqp_get_rpc_reply(conn), "Opening channel");

	amqp_exchange_declare(conn, 1, amqp_cstring_bytes(exchange),
		amqp_cstring_bytes(exchangetype), 0, 0, 0, 0,
		amqp_empty_table);
	die_on_amqp_error2(amqp_get_rpc_reply(conn), "Declaring exchange");

	die_on_amqp_error2(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS),
		"Closing channel");
	die_on_amqp_error2(amqp_connection_close(conn, AMQP_REPLY_SUCCESS),
		"Closing connection");
	die_on_error2(amqp_destroy_connection(conn), "Ending connection");
	int end = 0;
}

 

 

删除交换机

/**

 * amqp_exchange_delete

 *

 * @param [in] state connection state

 * @param [in] channel the channel to do the RPC on

 * @param [in] exchange exchange

 * @param [in] if_unused if_unused

 * @returns amqp_exchange_delete_ok_t

 */

AMQP_PUBLIC_FUNCTION

amqp_exchange_delete_ok_t *AMQP_CALL

    amqp_exchange_delete(amqp_connection_state_t state, amqp_channel_t channel,

                         amqp_bytes_t exchange, amqp_boolean_t if_unused);

 

向交换机绑定路由键

队列的消息来源于交换机,所以队列需要通过路由键与交换机建立联系,然后报备自己需要的消息。

/**

 * amqp_queue_bind

 *

 * @param [in] state connection state:连接对象

 * @param [in] channel the channel to do the RPC on:通道

 * @param [in] queue queue:待绑定的队列名称

 * @param [in] exchange exchange:与队列绑定的交换机名称

 * @param [in] routing_key routing_key:路由键

 * @param [in] arguments arguments

 * @returns amqp_queue_bind_ok_t

 */

AMQP_PUBLIC_FUNCTION

amqp_queue_bind_ok_t *AMQP_CALL amqp_queue_bind(

    amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t queue,

amqp_bytes_t exchange, amqp_bytes_t routing_key, amqp_table_t arguments);

从交换机解绑路由键

取消队列与交换机之间的关联。

/**

 * amqp_queue_unbind

 *

 * @param [in] state connection state:对象

 * @param [in] channel the channel to do the RPC on:通道

 * @param [in] queue queue:队列名称

 * @param [in] exchange exchange:交换机名称

 * @param [in] routing_key routing_key:路由键

 * @param [in] arguments arguments

 * @returns amqp_queue_unbind_ok_t

 */

AMQP_PUBLIC_FUNCTION

amqp_queue_unbind_ok_t *AMQP_CALL amqp_queue_unbind(

    amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t queue,

    amqp_bytes_t exchange, amqp_bytes_t routing_key, amqp_table_t arguments);

 

 

交换机之间绑定路由键

把队列与交换机,通过路由键建立交联,当交换机收到指定路由键的消息时,交会路由到之前绑定的队列中去。

/**

 * amqp_exchange_bind

 *

 * @param [in] state connection state:连接对象

 * @param [in] channel the channel to do the RPC on:通道

 * @param [in] destination destination:接收消息的交换机

 * @param [in] source source:发出消息的交换机

 * @param [in] routing_key routing_key:路由键

 * @param [in] arguments arguments

 * @returns amqp_exchange_bind_ok_t

 */

AMQP_PUBLIC_FUNCTION

amqp_exchange_bind_ok_t *AMQP_CALL

    amqp_exchange_bind(amqp_connection_state_t state, amqp_channel_t channel,

                       amqp_bytes_t destination, amqp_bytes_t source,

                       amqp_bytes_t routing_key, amqp_table_t arguments);

交换机之间解绑路由键

把队列与交换机通过路由键建立的交联进行解除,让队列与交换机解除关系。

 

/**

 * amqp_exchange_unbind

 *

 * @param [in] state connection state:连接对象

 * @param [in] channel the channel to do the RPC on:通道

 * @param [in] destination destination:

 * @param [in] source source

 * @param [in] routing_key routing_key

 * @param [in] arguments arguments

 * @returns amqp_exchange_unbind_ok_t

 */

AMQP_PUBLIC_FUNCTION

amqp_exchange_unbind_ok_t *AMQP_CALL

    amqp_exchange_unbind(amqp_connection_state_t state, amqp_channel_t channel,

                         amqp_bytes_t destination, amqp_bytes_t source,

                         amqp_bytes_t routing_key, amqp_table_t arguments);

 

4.3队列

声明队列

/**

 * amqp_queue_declare

 *

 * @param [in] state connection state:连接对象

 * @param [in] channel the channel to do the RPC on:通道

 * @param [in] queue queue:需要绑定的队列名称

 * @param [in] passive passive:检测queue是否存在,设为true,若queue存在则命令成功返回(调用其他参数不会影响queue属性),若不存在不会创建queue,返回错误。设为false,如果queue不存在则创建queue,调用成功返回。如果queue已经存在,并且匹配现在queue的话则成功返回,如果不匹配则queue声明失败。

 * @param [in] durable durable:是否持久化(写入到硬盘)

 * @param [in] exclusive exclusive:当前连接断开时,队列是否自动删除

 * @param [in] auto_delete auto_delete:没有消费者时,是否自动删除

 * @param [in] arguments arguments

 * @returns amqp_queue_declare_ok_t

 */

AMQP_PUBLIC_FUNCTION

amqp_queue_declare_ok_t *AMQP_CALL amqp_queue_declare(

    amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t queue,

    amqp_boolean_t passive, amqp_boolean_t durable, amqp_boolean_t exclusive,

amqp_boolean_t auto_delete, amqp_table_t arguments);

 

清空队列

清空队列里的数据

/**

 * amqp_queue_purge

 *

 * @param [in] state connection state:连接对象

 * @param [in] channel the channel to do the RPC on:通道

 * @param [in] queue queue:队列名称

 * @returns amqp_queue_purge_ok_t

 */

AMQP_PUBLIC_FUNCTION

amqp_queue_purge_ok_t *AMQP_CALL amqp_queue_purge(amqp_connection_state_t state,

                                                  amqp_channel_t channel,

                                                  amqp_bytes_t queue);

删除队列

/**

 * amqp_queue_delete

 *

 * @param [in] state connection state:连接对象

 * @param [in] channel the channel to do the RPC on:通道号

 * @param [in] queue queue:队列名称

 * @param [in] if_unused if_unused:当为真时,仅当队列不使用时删除

 * @param [in] if_empty if_empty:当为真时,仅当队列为空时删除

 * @returns amqp_queue_delete_ok_t:返回值

 */

AMQP_PUBLIC_FUNCTION

amqp_queue_delete_ok_t *AMQP_CALL amqp_queue_delete(

    amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t queue,

amqp_boolean_t if_unused, amqp_boolean_t if_empty);

 

 

 

 

4.4生产者

/**

  * 发布一条消息到broker

  *

  * 使用路由密钥在exchange上发布消息。

  *

  * 请注意,在AMQ协议级别basic.publish是一个异步方法:

  * 这意味着broker发生的错误情况(例如发布到不存在的exchange)将不会反映在此函数的返回值中。

  *

  * \param [in] state 连接对象

  * \param [in] channel 通道标识符

  * \param [in] exchange broker需要发布到的exchange

  * \param [in] routing_key 发布消息使用的路由秘钥

  * \param [in] mandatory 向broker表明该消息必须路由到一个队列。如果broker不能这样做,

  *             它应该用一个basic.return方法来回应。

  * \param [in] immediate 向broker表明该消息必须立即传递给消费者,如果broker不能这样做,

  *             它应该用一个basic.return方法来回应。

  * \param [in] properties 与消息相关的属性

  * \param [in] body 消息体

  * \return 成功返回AMQP_STATUS_OK,失败返回amqp_status_enum值

  *         注意:请注意,basic.publish是一个异步方法,此函数的返回值仅指示消息数据已

  *         成功传输到代理.它并不表示broker发生的故障,例如发布到不存在的exchange.

  *         可能的错误值:

  *         - AMQP_STATUS_TIMER_FAILURE:系统计时器设施返回错误,消息未被发送。

  *         - AMQP_STATUS_HEARTBEAT_TIMEOUT: 等待broker的心跳连接超时,消息未被发送

  *         - AMQP_STATUS_NO_MEMORY:分配内存失败,消息未被发送

  *         - AMQP_STATUS_TABLE_TOO_BIG:属性中的table太大而不适合单个框架,消息未被发送

  *         - AMQP_STATUS_CONNECTION_CLOSED:连接被关闭。

  *         - AMQP_STATUS_SSL_ERROR:发生SSL错误。

  *         - AMQP_STATUS_TCP_ERROR:发生TCP错误,errno或WSAGetLastError()可能提供更多的信息

  *

  */

AMQP_PUBLIC_FUNCTION

int AMQP_CALL amqp_basic_publish(

    amqp_connection_state_t state, amqp_channel_t channel,

    amqp_bytes_t exchange, amqp_bytes_t routing_key, amqp_boolean_t mandatory,

    amqp_boolean_t immediate, struct amqp_basic_properties_t_ const *properties,

    amqp_bytes_t body);                                

 

 

 

 

4.5消费者

消费方式分push与pull。RabbitMQ-C的example和网上的博客都是通过consume方式获取数据,但consume是通过推送的方式被动消费数据,当调用amqp_basic_consume开始一个消费者后,服务器就开始推送数据,而调用amqp_consume_message只是从本地的缓冲区中读取数据,每次服务器都推送了300条数据;

而我想一条一条的主动取,example中并没有关于主动get数据的方式。后来经过多次读源码,写例子,才发现amqp_basic_get就是一条一条的取数据,当然这个函数不能像amqp_basic_consume一样仅仅调用一次;而是在每次amqp_read_message之前都要调用amqp_basic_get方法;

如果只调用一次amqp_basic_get那么当我们第二次调用amqp_read_message的时候就会阻塞,所以它们必须成对出现。

4.5.1订阅

服务端主动给消费者推送消息,通过两个函数配合使用,先调用amqp_basic_consume开始一个消费者后,服务器就开始推送数据,再调用amqp_consume_message从本地的缓冲区中读取数据,每次服务器都推送了300条数据。

 

/**

 * amqp_basic_consume:开始一个队列消费者

 *

 * @param [in] state connection state:连接对象

 * @param [in] channel the channel to do the RPC on:通道

 * @param [in] queue queue:队列名称

 * @param [in] consumer_tag consumer_tag:消费者标签

 * @param [in] no_local no_local:填false,属于amqp标准,rabbitmq没有实现

 * @param [in] no_ack no_ack:如果为true,消费消息后直接从队列清除,为false,需要

 * 人工调用amqp_basic_ack函数后,消息才会从队列清除。

 * @param [in] exclusive exclusive:排他消费者,即这个队列只能由一个消费者消费.适用于

 * 任务不允许进行并发处理的情况下.比如系统对接

 * @param [in] arguments arguments

 * @returns amqp_basic_consume_ok_t

 */

AMQP_PUBLIC_FUNCTION

amqp_basic_consume_ok_t *AMQP_CALL amqp_basic_consume(

    amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t queue,

    amqp_bytes_t consumer_tag, amqp_boolean_t no_local, amqp_boolean_t no_ack,

amqp_boolean_t exclusive, amqp_table_t arguments);

 

 

/**

 * Wait for and consume a message:等待并消费消息

 *

 * Waits for a basic.deliver method on any channel, upon receipt of

 * basic.deliver it reads that message, and returns. If any other method is

 * received before basic.deliver, this function will return an amqp_rpc_reply_t

 * with ret.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION, and

 * ret.library_error == AMQP_STATUS_UNEXPECTED_STATE. The caller should then

 * call amqp_simple_wait_frame() to read this frame and take appropriate action.

 *

 * This function should be used after starting a consumer with the

 * amqp_basic_consume() function

 *

 * \param [in,out] state the connection object:连接对象

 * \param [in,out] envelope a pointer to a amqp_envelope_t object. Caller

 *                 should call #amqp_destroy_envelope() when it is done using

 *                 the fields in the envelope object. The caller is responsible

 *                 for allocating/destroying the amqp_envelope_t object itself.

 *返回一个指针,指向一个对象,这个对象使用后,需要人工调用amqp_destroy_envelope

 *释放。

 * \param [in] timeout a timeout to wait for a message delivery. Passing in

 *             NULL will result in blocking behavior.:等待时间,为NULL将阻塞

 * \param [in] flags pass in 0. Currently unused.:无效

 * \returns a amqp_rpc_reply_t object.  ret.reply_type == AMQP_RESPONSE_NORMAL

 *          on success. If ret.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION,

 *          and ret.library_error == AMQP_STATUS_UNEXPECTED_STATE, a frame other

 *          than AMQP_BASIC_DELIVER_METHOD was received, the caller should call

 *          amqp_simple_wait_frame() to read this frame and take appropriate

 *          action.

 *

 * \since v0.4.0

 */

AMQP_PUBLIC_FUNCTION

amqp_rpc_reply_t AMQP_CALL amqp_consume_message(amqp_connection_state_t state,

                                                amqp_envelope_t *envelope,

                                                struct timeval *timeout,

                                                int flags);

 

4.5.2拉取

amqp_basic_get与amqp_read_message配合,一条一条主动提取消息。如果只调用一次amqp_basic_get那么当我们第二次调用amqp_read_message的时候就会阻塞,所以它们必须成对出现。

 

/**

 * Do a basic.get:单条提取消息

 *

 * Synchonously polls the broker for a message in a queue, and

 * retrieves the message if a message is in the queue.:从队列中提取消息,一次提取一

 *条,这是主动提取,适合某些主动处理消息的场景

 * \param [in] state the connection object:连接对象

 * \param [in] channel the channel identifier to use:通道

 * \param [in] queue the queue name to retrieve from:队列

 * \param [in] no_ack if true the message is automatically ack'ed

 *              if false amqp_basic_ack should be called once the message

 *              retrieved has been processed:是否要人工回馈

 * \return amqp_rpc_reply indicating success or failure

 *

 * \since v0.1

 */

AMQP_PUBLIC_FUNCTION

amqp_rpc_reply_t AMQP_CALL amqp_basic_get(amqp_connection_state_t state,

                                          amqp_channel_t channel,

                                          amqp_bytes_t queue,

                                          amqp_boolean_t no_ack);

 

 

/**

 * Reads the next message on a channel:读取消息

 *读取指定通道上的队列上的消息,需要与amqp_basic_get()配合使用

 * Reads a complete message (header + body) on a specified channel. This

 * function is intended to be used with amqp_basic_get() or when an

 * AMQP_BASIC_DELIVERY_METHOD method is received.

 *

 * \param [in,out] state the connection object:连接对象

 * \param [in] channel the channel on which to read the message from:通道

 * \param [in,out] message a pointer to a amqp_message_t object. Caller should

 *                 call amqp_message_destroy() when it is done using the

 *                 fields in the message object.  The caller is responsible for

 *                 allocating/destroying the amqp_message_t object itself.

 * 指向返回消息的指针,需要人工调用amqp_message_destroy() 接口释放

 * \param [in] flags pass in 0. Currently unused.:废弃

 * \returns a amqp_rpc_reply_t object. ret.reply_type == AMQP_RESPONSE_NORMAL on

 * success.

 *

 * \since v0.4.0

 */

AMQP_PUBLIC_FUNCTION

amqp_rpc_reply_t AMQP_CALL amqp_read_message(amqp_connection_state_t state,

                                             amqp_channel_t channel,

                                             amqp_message_t *message,

                                             int flags);

 

 

/**

 * Acknowledges a message:回馈指定消息

 *

 * Does a basic.ack on a received message:对消费后的消息进行回馈

 *

 * \param [in] state the connection object:连接对象

 * \param [in] channel the channel identifier:通道

 * \param [in] delivery_tag the delivery tag of the message to be ack'd:传输标签

 * \param [in] multiple if true, ack all messages up to this delivery tag, if

 *              false ack only this delivery tag:传输标签

 * \return 0 on success,  0 > on failing to send the ack to the broker.

 *            this will not indicate failure if something goes wrong on the

 *            broker

 *

 * \since v0.1

 */

AMQP_PUBLIC_FUNCTION

int AMQP_CALL amqp_basic_ack(amqp_connection_state_t state,

                             amqp_channel_t channel, uint64_t delivery_tag,

                             amqp_boolean_t multiple);

 

delivery_tag如何获得?以下是伪代码:

amqp_rpc_reply_t rpc_reply;

do {

         rpc_reply = amqp_basic_get(conn, 1,queuename, 0);

} while (rpc_reply.reply_type == AMQP_RESPONSE_NORMAL &&

         rpc_reply.reply.id == AMQP_BASIC_GET_EMPTY_METHOD

         /*&& amqp_time_has_past(deadline) == AMQP_STATUS_OK*/);

 

amqp_message_t message;

amqp_rpc_reply_t rpc_reply2 = amqp_read_message(conn, 1, &message, 0);

 

amqp_method_t method = rpc_reply.reply;

 

if (AMQP_BASIC_GET_OK_METHOD == method.id)

{

         amqp_basic_ack_t *s;

         s = (amqp_basic_ack_t *) method.decoded;

         int nRe = amqp_basic_ack(conn, 1, s->delivery_tag, 0);

         int i = 0;

}

 

而通过amqp_consume_message接口消费的消息,如果要回馈的话,delivery_tag在返回的amqp_envelope_t变量里。

 

 

 

你可能感兴趣的:(RabbitMQ)