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是如果出現如圖的錯誤,可以去掉ENABLE_SSL_SUPPORT括號裏的對勾。 

 

在以上生成的工程目錄下的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 <amqp.h>
#include <amqp_tcp_socket.h>
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變量裏。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章