1) C++ 获取消息数据
amqp_rpc_reply_t ret;
timeval tvTimeout;
tvTimeout.tv_sec = 1;
tvTimeout.tv_usec = 0;
ret = amqp_consume_message(conn, &envelope, &valTimeOut, 0);
if (AMQP_RESPONSE_NORMAL == ret.reply_type)
{
std::string strAMQPMsg((char*)envelope.message.body.bytes, envelope.message.body.len);
}
误区: std::string strAMQPMsg = char*)envelope.message.body.bytes 存在多余的数据
误区: 没有设置接收超时,而是直接传递NULL,导致函数进入死循环
2)发送消息的时候,返回错误信息:AMQP_STATUS_SOCKET_ERROR
AMQP_STATUS_SOCKET_ERROR = -0x0009, /**< A socket error occurred */
服务器在一定时间之内,收到客户端的消息,就会主动断开连接,因此客户端需要跟服务器Broker重新建立连接,如果不想断开连接,需要发送心跳
3)确认数据是否已经发送成功
关于消费者就不用代码来获取消息了,直接在RabbitMQ Management点击某个队列的名字,然后Get Message(s) 即可获取消息内容
4)指定消息的超时时间
某些实际的应用场景中会产生许多过期的消息时间,可以通过设置amqp_basic_properties_t的超时时间参数expiration来解决队列中的超时数据过多的问题
amqp_basic_properties_t props;
props._flags = AMQP_BASIC_EXPIRATION_FLAG;
props.expiration = amqp_cstring_bytes("10000");//超时10秒
amqp_basic_publish(conn, channnel, exchange, queue, 0, 0, &props, message);
5)声明队列,返回错误信息:AMQP_RESPONSE_SERVER_EXCEPTION
原因:1.交换机是否创建成功 2.声明的队列是否已经创建过,并且已经存在的队列跟现在的队列的属性不一致,例如auto_delete自动删除属性,或者durable持久化属性
导致的问题:当返回该错误,说明跟broker的连接已经中断,必须重新建立连接,否则,继续调用其他函数接口会一直阻塞
解决: 通过web手动删除队列
6)只知道队列的情况下获取数据
实际上说明声明的交换机和队列都必须唯一
amqp_connection_state_t connState = amqp_new_connection();
amqp_socket_t *pSocket = amqp_tcp_socket_new(connState);
if (!pSocket) {
amqp_connection_close(connState, AMQP_REPLY_SUCCESS);
amqp_destroy_connection(connState);
std::cout << "跟消息服务器创建连接失败" << std::endl;
return;
}
int nConnStatus = amqp_socket_open(pSocket, strIP.c_str(), nPort);
if (AMQP_STATUS_OK != nConnStatus) {
amqp_connection_close(connState, AMQP_REPLY_SUCCESS);
amqp_destroy_connection(connState);
return;
}
amqp_rpc_reply_t rpcReply = amqp_login(connState, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, strUserName.c_str(), strPassword.c_str());
if (AMQP_RESPONSE_NORMAL != rpcReply.reply_type)
{
std::cout << "登陆消息服务器失败" << std::endl;
return;
}
amqp_channel_open(connState, 1);
amqp_basic_consume(connState, 1, amqp_cstring_bytes("passerby-000001"), amqp_empty_bytes, 0, 1, 0, amqp_empty_table);
amqp_frame_t frame;
std::cout << "登陆消息服务器成功,开始接收数据" << std::endl;
while (1)
{
amqp_envelope_t envelope;
amqp_maybe_release_buffers(connState);
timeval tvTimeout;
tvTimeout.tv_sec = 10;
tvTimeout.tv_usec = 0;
amqp_rpc_reply_t ret = amqp_consume_message(connState, &envelope, &tvTimeout, 0);
if (AMQP_RESPONSE_NORMAL != ret.reply_type)
{
if (AMQP_STATUS_SOCKET_ERROR == ret.library_error)
{
std::cout << "跟消息服务器连接中断,清理资源,重连连接" << std::endl;
break;
}
if (AMQP_STATUS_TIMEOUT == ret.library_error)
{
std::cout << "等待消息服务器消息超时,继续等待" << std::endl;
continue;
}
std::cout << "跟消息服务器连接出现异常,清理资源,重连连接" << std::endl;
break;
}
else
{
std::string strRecvMsg((char*)envelope.message.body.bytes, envelope.message.body.len);
std::cout << "接收到的抓拍信息:" << strRecvMsg<< std::endl;
amqp_destroy_envelope(&envelope);
continue;
}
}
amqp_channel_close(connState, 1, AMQP_REPLY_SUCCESS);
amqp_connection_close(connState, AMQP_REPLY_SUCCESS);
amqp_destroy_connection(connState);
7)生产者不产生队列,消费者通过指定的交换机和routing-key,创建队列,然后将该队列绑定到交换机上
char const* pszExchange = "passerByExchange";
char const* pszRoutingKey = "passerby-000001";
amqp_connection_state_t connState = amqp_new_connection();
amqp_socket_t* pSocket = amqp_tcp_socket_new(connState);
if (!pSocket) {
amqp_connection_close(connState, AMQP_REPLY_SUCCESS);
amqp_destroy_connection(connState);
return;
}
int nStatus = amqp_socket_open(pSocket, strIP.c_str(), nPort);
if (nStatus) {
amqp_connection_close(connState, AMQP_REPLY_SUCCESS);
amqp_destroy_connection(connState);
return;
}
amqp_rpc_reply_t replyLogin = amqp_login(connState, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, strUserName.c_str(), strPassword.c_str());
if (AMQP_RESPONSE_NORMAL != replyLogin.reply_type)
{
std::cout << "登陆消息服务器失败" << std::endl;
return;
}
amqp_channel_open(connState, 1);
amqp_queue_declare_ok_t *r = amqp_queue_declare(
connState, 1, amqp_empty_bytes, 0, 0, 0, 1, amqp_empty_table);
amqp_bytes_t queueName = amqp_bytes_malloc_dup(r->queue);
if (queueName.bytes == NULL)
{
amqp_bytes_free(queueName);
amqp_connection_close(connState, AMQP_REPLY_SUCCESS);
amqp_destroy_connection(connState);
return;
}
amqp_queue_bind(connState, 1, queueName, amqp_cstring_bytes(pszExchange),
amqp_cstring_bytes(pszRoutingKey), amqp_empty_table);
amqp_basic_consume(connState, 1, queueName, amqp_empty_bytes, 0, 1, 0,
amqp_empty_table);
amqp_frame_t frame;
while (1)
{
amqp_rpc_reply_t ret;
amqp_envelope_t envelope;
amqp_maybe_release_buffers(connState);
timeval tvTimeout;
tvTimeout.tv_sec = 10;
tvTimeout.tv_usec = 0;
ret = amqp_consume_message(connState, &envelope, &tvTimeout, 0);
if (AMQP_RESPONSE_NORMAL != ret.reply_type)
{
if (AMQP_STATUS_TIMEOUT == ret.library_error)
{
std::cout << "接收消息超时" << std::endl;
continue;
}
std::cout << "连接消息服务器异常,清理资源退出" << std::endl;
break;
}
else
{
std::string strRecvMsg((char*)envelope.message.body.bytes, envelope.message.body.len);
std::string strGBK = UTF8ToGBK(strRecvMsg.c_str());
amqp_destroy_envelope(&envelope);
}
}
amqp_channel_close(connState, 1, AMQP_REPLY_SUCCESS);
amqp_connection_close(connState, AMQP_REPLY_SUCCESS);
amqp_destroy_connection(connState);
8)amqp_basic_consume函数不能连续调用多次同时消费多个队列
代码如下:
amqp_basic_consume(connState, 1, amqp_cstring_bytes("alarm"), amqp_empty_bytes, 0, 1, 0, amqp_empty_table);
amqp_basic_consume(connState, 1, amqp_cstring_bytes("capture"), amqp_empty_bytes, 0, 1, 0, amqp_empty_table);
只能执行第一句代码,第二句代码会一直阻塞
9)登陆MQ服务器,进行心跳交互代码
amqp_rpc_reply_t replyLogin = amqp_login(conn, "/", 0, 131072, 120, AMQP_SASL_METHOD_PLAIN, strUserName.c_str(), strPassword.c_str());
第五个参数,指定了跟服务器多少秒发送一次心跳,如果不发心跳,跟服务器在连接一段时间之后,断开,当然,也要考虑到长连接也可能在网络异常情况下断开