rabbitmq_base.cpp 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046
  1. #include "rabbitmq_base.h"
  2. Rabbitmq_base::Rabbitmq_base()
  3. {
  4. m_rabbitmq_status = RABBITMQ_STATUS_UNKNOW;
  5. mp_connect = NULL;
  6. mp_socket = NULL;
  7. m_port = 0;
  8. mp_receive_analysis_thread = NULL;
  9. mp_send_thread = NULL;
  10. mp_encapsulate_status_thread = NULL;
  11. m_encapsulate_status_cycle_time = 1000;//默认1000ms,就自动封装一次状态信息
  12. check_msg_callback = NULL;
  13. check_executer_callback = NULL;
  14. execute_msg_callback = NULL;
  15. encapsulate_status_callback = NULL;
  16. }
  17. Rabbitmq_base::~Rabbitmq_base()
  18. {
  19. rabbitmq_uninit();
  20. }
  21. //初始化 通信 模块。如下三选一
  22. Error_manager Rabbitmq_base::rabbitmq_init()
  23. {
  24. return rabbitmq_init_from_protobuf(RABBITMQ_PARAMETER_PATH);
  25. }
  26. //初始化 通信 模块。从文件读取
  27. Error_manager Rabbitmq_base::rabbitmq_init_from_protobuf(std::string prototxt_path)
  28. {
  29. Rabbitmq_proto::Rabbitmq_parameter_all t_rabbitmq_parameter_all;
  30. if(! proto_tool::read_proto_param(prototxt_path,t_rabbitmq_parameter_all) )
  31. {
  32. return Error_manager(RABBITMQ_READ_PROTOBUF_ERROR,MINOR_ERROR,
  33. "rabbitmq_init_from_protobuf read_proto_param failed");
  34. }
  35. return rabbitmq_init_from_protobuf(t_rabbitmq_parameter_all);
  36. }
  37. //初始化 通信 模块。从protobuf读取
  38. Error_manager Rabbitmq_base::rabbitmq_init_from_protobuf(Rabbitmq_proto::Rabbitmq_parameter_all &rabbitmq_parameter_all)
  39. {
  40. LOG(INFO) << " ---Rabbitmq_base::rabbitmq_init_from_protobuf() run--- "<< this;
  41. int t_status=0; //状态
  42. amqp_rpc_reply_t t_reply; //reply答复结果
  43. Error_manager t_error;
  44. m_rabbitmq_parameter_all = rabbitmq_parameter_all;
  45. //amqp_new_connection 新建amqp的连接配置,里面只有连接状态参数
  46. // 返回amqp_connection_state_t_ *, 函数内部分配内存, amqp_destroy_connection()可以释放内存, 内存不为空则成功
  47. mp_connect = amqp_new_connection();
  48. if ( mp_connect == NULL )
  49. {
  50. return Error_manager(Error_code::RABBITMQ_AMQP_NEW_CONNECTION_ERROR, Error_level::MINOR_ERROR,
  51. "amqp_new_connection fun error ");
  52. }
  53. //amqp_tcp_socket_new 新建tcp_socket连接
  54. // 返回amqp_socket_t *, 函数内部分配内存, amqp_connection_close()可以释放内存, 内存不为空则成功
  55. mp_socket = amqp_tcp_socket_new(mp_connect);
  56. if ( mp_socket == NULL )
  57. {
  58. return Error_manager(Error_code::RABBITMQ_AMQP_TCP_SOCKET_NEW_ERROR, Error_level::MINOR_ERROR,
  59. "amqp_tcp_socket_new fun error ");
  60. }
  61. //载入外部参数
  62. if (rabbitmq_parameter_all.rabbitmq_parameters().has_ip() &&
  63. rabbitmq_parameter_all.rabbitmq_parameters().has_port() &&
  64. rabbitmq_parameter_all.rabbitmq_parameters().has_user() &&
  65. rabbitmq_parameter_all.rabbitmq_parameters().has_password() )
  66. {
  67. m_ip = rabbitmq_parameter_all.rabbitmq_parameters().ip();
  68. m_port = rabbitmq_parameter_all.rabbitmq_parameters().port();
  69. m_user = rabbitmq_parameter_all.rabbitmq_parameters().user();
  70. m_password = rabbitmq_parameter_all.rabbitmq_parameters().password();
  71. }
  72. else
  73. {
  74. return Error_manager(Error_code::RABBITMQ_PROTOBUF_LOSS_ERROR, Error_level::MINOR_ERROR,
  75. " rabbitmq_parameter_all.rabbitmq_parameters() The data is not complete ");
  76. }
  77. //amqp_socket_open 打开socket连接, 输入ip和port,
  78. // 成功返回AMQP_STATUS_OK = 0x0, 失败返回错误状态码, 详见 enum amqp_status_enum_
  79. //只需要设置配置服务器的ip和port, 不需要配置子节点客户端的ip和port, 在后面配置channel通道时,进行设置.
  80. t_status = amqp_socket_open(mp_socket, m_ip.c_str(), m_port);
  81. if ( t_status != AMQP_STATUS_OK )
  82. {
  83. return Error_manager(Error_code::RABBITMQ_AMQP_SOCKET_OPEN_ERROR, Error_level::MINOR_ERROR,
  84. amqp_error_to_string(t_status, "amqp_socket_open").c_str() );
  85. }
  86. //amqp_login() 登录代理服务器,
  87. //输入 连接参数结构体 amqp_connection_state_t,
  88. //输入 连接地址, 前面 amqp_socket_open() 已经输入了,这里默认写"/"
  89. //输入 连接通道最大值, 默认值0表示没有限制
  90. //输入 连接帧率最大值, 默认值是131072 (128KB)
  91. //输入 心跳帧之间的秒数, 默认值0禁用心跳
  92. //输入 身份验证模式, AMQP_SASL_METHOD_PLAIN, 追加用户名和密码
  93. // AMQP_SASL_METHOD_EXTERNAL, 追加身份证
  94. //返回 结果的结构体 amqp_rpc_reply_t
  95. // amqp_response_type_enum reply_type 登录成功是 AMQP_RESPONSE_NORMAL
  96. // 失败:如果是 reply_type == AMQP_RESPONSE_SERVER_EXCEPTION, 服务器连接错误, 错误信息在 amqp_method_t reply
  97. // 失败:如果是 reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION, 库函数错误, 错误信息在 int library_error
  98. t_reply = amqp_login(mp_connect, "/", 0, 131072, 0,
  99. AMQP_SASL_METHOD_PLAIN, m_user.c_str(), m_password.c_str());
  100. if ( t_reply.reply_type != AMQP_RESPONSE_NORMAL )
  101. {
  102. return Error_manager(Error_code::RABBITMQ_AMQP_LOGIN_ERROR, Error_level::MINOR_ERROR,
  103. amqp_error_to_string(t_reply, "amqp_login").c_str() );
  104. }
  105. //清除channel_map, 通道的缓存,防止重复开启, (channel允许重复使用, 但是不能重复初始化)
  106. m_channel_map.clear();
  107. //创建通道队列消费者, (交换机和永久队列不在代码里创建,请在服务器上手动创建)
  108. t_error = rabbitmq_new_channel_queue_consume(rabbitmq_parameter_all);
  109. std::cout<<"rabbitmq config: "<<rabbitmq_parameter_all.DebugString()<<std::endl;
  110. if ( t_error != Error_code::SUCCESS )
  111. {
  112. return t_error;
  113. }
  114. //启动通信, 开启线程, run thread
  115. t_error = rabbitmq_run();
  116. if ( t_error != Error_code::SUCCESS )
  117. {
  118. return t_error;
  119. }
  120. return Error_code::SUCCESS;
  121. }
  122. //创建通道队列消费者, (交换机和永久队列不在代码里创建,请在服务器上手动创建)
  123. Error_manager Rabbitmq_base::rabbitmq_new_channel_queue_consume(Rabbitmq_proto::Rabbitmq_parameter_all &rabbitmq_parameter_all)
  124. {
  125. int t_status=0; //状态
  126. amqp_rpc_reply_t t_reply; //reply答复结果
  127. Error_manager t_error;
  128. ///Rabbitmq 接受的通道,队列和消费者, 多个
  129. for(int i=0;i<rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_reciever_vector_size();++i)
  130. {
  131. //Rabbitmq 配置的通道,队列和消费者,
  132. Rabbitmq_proto::Rabbitmq_channel_queue_consume t_inf =
  133. rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_reciever_vector(i);
  134. //通道查重,防止重复开启(channel允许重复使用, 但是不能重复初始化)
  135. if ( m_channel_map.find(t_inf.channel()) == m_channel_map.end() )
  136. {
  137. //amqp_channel_open() 打开连接通道, 同一台电脑可以多个进程和线程进行连接服务器, 每个连接需要自己独特的通道.
  138. amqp_channel_open(mp_connect, t_inf.channel());
  139. //amqp_get_rpc_reply() 获取当前网络连接的状态结果.
  140. t_reply = amqp_get_rpc_reply(mp_connect);
  141. if ( t_reply.reply_type != AMQP_RESPONSE_NORMAL )
  142. {
  143. return Error_manager(Error_code::RABBITMQ_AMQP_CHANNEL_OPEN_ERROR, Error_level::MINOR_ERROR,
  144. amqp_error_to_string(t_reply, "amqp_channel_open").c_str() );
  145. }
  146. if ( t_inf.consume_no_ack() == 0 )
  147. {
  148. //amqp_basic_qos设置通道每次只能接受一条消息, 直到该消息被ack,才能接受下一条.状态消息可以继续接受
  149. //uint16_t prefetch_count 同时接受消息的个数, 这里固定写1,
  150. //配合 amqp_basic_qos 和 amqp_basic_ack , 来阻塞这个通道的接受消息
  151. //注:请求消息no_ack==0, 当接受一条指令后,该通道被阻塞,其他通道仍然正常接受, 等到任务被执行完,手动调用amqp_basic_ack函数, 则可以继续接受请求消息.
  152. //注:状态消息no_ack==1, 当接受一条指令后,该状态消息立刻被删除,然后可以继续接受下一条状态消息.
  153. amqp_basic_qos(mp_connect, t_inf.channel(), 0, PREFETCH_COUNT, 0);
  154. }
  155. m_channel_map[t_inf.channel()] = true;
  156. }
  157. //临时队列需要代码创建, 永久队列需要在服务器上提前手动创建
  158. if ( t_inf.queue_durable() == 0 )
  159. {
  160. //amqp_queue_declare() 队列声明, 就是创建新的队列.
  161. //输入 amqp_connection_state_t state 连接状态参数的结构体
  162. //输入 amqp_channel_t channel 连接通道的编号
  163. //输入 amqp_bytes_t queue 队列名称,可以手动命名,如果写空,系统就会自动分配, 手动写amqp_cstring_bytes("abcdefg"), 默认空 amqp_empty_bytes
  164. //输入 amqp_boolean_t passive 是否被动,默认0
  165. //输入 amqp_boolean_t durable 是否持久,默认0, 节点代码可以创建临时队列(所有权归节点), 服务器手动创建永久队列(所有权归服务器)
  166. // 1表示永久队列,当节点死掉,队列在服务器保留,仍然可以接受数据,节点上线后,可以接受掉线期间的所有数据
  167. // 0表示临时队列,当节点死掉,队列消失,不再接受数据,直到下次恢复正常
  168. //输入 amqp_boolean_t exclusive 是否独立,默认0
  169. //输入 amqp_boolean_t auto_delete 是否自动删除,默认0, 1表示消息被消费者接受后,就自动删除消息, 当接收端断连后,队列也会才删除,
  170. // 一般情况下设为0,然后让接受者手动删除.
  171. //输入 amqp_table_t arguments 预留参数,默认空 amqp_empty_table
  172. //返回 amqp_queue_declare_ok_t * 返回结果
  173. amqp_queue_declare(mp_connect, t_inf.channel(), amqp_cstring_bytes(t_inf.queue_name().c_str()),
  174. t_inf.queue_passive(), t_inf.queue_durable(), t_inf.queue_exclusive(),
  175. t_inf.queue_auto_delete(), amqp_empty_table);
  176. //amqp_queue_bind 队列绑定, 将队列加载到服务器的交换机下面, 交换机收到消息后,就会检查key,然后放到指定的队列.
  177. //输入 amqp_connection_state_t state 连接状态参数的结构体
  178. //输入 amqp_channel_t channel 连接通道的编号
  179. //输入 amqp_bytes_t queue 队列名称,
  180. //输入 amqp_bytes_t exchange 交换机模式字符串
  181. //输入 amqp_bytes_t bindingkey 绑定密钥字符串, 交换机的判断规则. 发送端的 routingkey 和 接收端的 bindingkey 需要保持一致
  182. //输入 amqp_table_t arguments 预留参数,默认空 amqp_empty_table
  183. //返回 amqp_queue_bind_ok_t * 返回结果
  184. //注注注注注意了, 队列绑定交换机时,必须保证交换机是有效的.否则报错
  185. amqp_queue_bind(mp_connect, t_inf.channel(), amqp_cstring_bytes(t_inf.queue_name().c_str()),
  186. amqp_cstring_bytes(t_inf.exchange_name().c_str()),
  187. amqp_cstring_bytes(t_inf.binding_key().c_str()), amqp_empty_table);
  188. amqp_rpc_reply_t t_reply = amqp_get_rpc_reply(mp_connect);
  189. if ( t_reply.reply_type != AMQP_RESPONSE_NORMAL )
  190. {
  191. return Error_manager(Error_code::RABBITMQ_AMQP_QUEUE_BIND_ERROR, Error_level::MINOR_ERROR,
  192. amqp_error_to_string(t_reply, "amqp_queue_bind").c_str() );
  193. }
  194. }
  195. //amqp_basic_consume 创建基本类型的消费者,就是接收端, 消费者绑定队列,只能接受一个队列里面的消息
  196. //输入 amqp_connection_state_t state 连接状态参数的结构体
  197. //输入 amqp_channel_t channel 连接通道的编号
  198. //输入 amqp_bytes_t queue 队列名称,
  199. //输入 amqp_bytes_t consumer_tag 消费者名称
  200. //输入 amqp_boolean_t no_local 是否非本地, 默认0,表示本地
  201. //输入 amqp_boolean_t no_ack, 是否确认应答,默认0,表示接收后需要应答
  202. //输入 amqp_boolean_t exclusive 是否独立,默认0
  203. //输入 amqp_table_t arguments 预留参数,默认空 amqp_empty_table
  204. //返回 amqp_basic_consume_ok_t * 返回结果
  205. //注注注注注意了, 接受端绑定队列时,必须保证队列是有效的,否则报错,
  206. amqp_basic_consume(mp_connect, t_inf.channel(), amqp_cstring_bytes(t_inf.queue_name().c_str()),
  207. amqp_cstring_bytes(t_inf.consume_name().c_str()), t_inf.consume_no_local(),
  208. t_inf.consume_no_ack(), t_inf.consume_exclusive(), amqp_empty_table);
  209. amqp_rpc_reply_t t_reply = amqp_get_rpc_reply(mp_connect);
  210. if ( t_reply.reply_type != AMQP_RESPONSE_NORMAL )
  211. {
  212. return Error_manager(Error_code::RABBITMQ_AMQP_NEW_CONSUME_ERROR, Error_level::MINOR_ERROR,
  213. amqp_error_to_string(t_reply, "amqp_basic_consume").c_str() );
  214. }
  215. }
  216. //Rabbitmq 发送请求的通道
  217. for(int i=0;i<rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_request_vector_size();++i)
  218. {
  219. //Rabbitmq 配置发送通道
  220. Rabbitmq_proto::Rabbitmq_channel_queue_consume t_inf1 =
  221. rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_request_vector(i);
  222. //通道查重,防止重复开启(channel允许重复使用, 但是不能重复初始化)
  223. if ( m_channel_map.find(t_inf1.channel()) == m_channel_map.end() )
  224. {
  225. //amqp_channel_open() 打开连接通道, 同一台电脑可以多个进程和线程进行连接服务器, 每个连接需要自己独特的通道.
  226. amqp_channel_open(mp_connect, t_inf1.channel());
  227. //amqp_get_rpc_reply() 获取当前网络连接的状态结果.
  228. t_reply = amqp_get_rpc_reply(mp_connect);
  229. if ( t_reply.reply_type != AMQP_RESPONSE_NORMAL )
  230. {
  231. return Error_manager(Error_code::RABBITMQ_AMQP_CHANNEL_OPEN_ERROR, Error_level::MINOR_ERROR,
  232. amqp_error_to_string(t_reply, "amqp_channel_open").c_str() );
  233. }
  234. m_channel_map[t_inf1.channel()] = true;
  235. }
  236. }
  237. //Rabbitmq 发送状态的通道
  238. for(int i=0;i<rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_status_vector_size();++i)
  239. {
  240. //Rabbitmq 配置发送通道
  241. Rabbitmq_proto::Rabbitmq_channel_queue_consume t_inf2 =
  242. rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_status_vector(i);
  243. //通道查重,防止重复开启(channel允许重复使用, 但是不能重复初始化)
  244. if ( m_channel_map.find(t_inf2.channel()) == m_channel_map.end() )
  245. {
  246. //amqp_channel_open() 打开连接通道, 同一台电脑可以多个进程和线程进行连接服务器, 每个连接需要自己独特的通道.
  247. amqp_channel_open(mp_connect, t_inf2.channel());
  248. //amqp_get_rpc_reply() 获取当前网络连接的状态结果.
  249. t_reply = amqp_get_rpc_reply(mp_connect);
  250. if ( t_reply.reply_type != AMQP_RESPONSE_NORMAL )
  251. {
  252. return Error_manager(Error_code::RABBITMQ_AMQP_CHANNEL_OPEN_ERROR, Error_level::MINOR_ERROR,
  253. amqp_error_to_string(t_reply, "amqp_channel_open").c_str() );
  254. }
  255. m_channel_map[t_inf2.channel()] = true;
  256. }
  257. }
  258. return Error_code::SUCCESS;
  259. }
  260. //启动通信, 开启线程, run thread
  261. Error_manager Rabbitmq_base::rabbitmq_run()
  262. {
  263. //启动 线程。
  264. //接受线程默认循环, 内部的 amqp_consume_message 进行等待, 超时1ms
  265. m_receive_analysis_condition.reset(false, true, false);
  266. mp_receive_analysis_thread = new std::thread(&Rabbitmq_base::receive_analysis_thread, this);
  267. //发送线程默认循环, 内部的wait_and_pop进行等待,
  268. m_send_condition.reset(false, true, false);
  269. mp_send_thread = new std::thread(&Rabbitmq_base::send_thread, this);
  270. //封装线程默认等待, ...., 超时1秒, 超时后主动 封装心跳和状态信息,
  271. m_encapsulate_status_condition.reset(false, false, false);
  272. mp_encapsulate_status_thread = new std::thread(&Rabbitmq_base::encapsulate_status_thread, this);
  273. m_rabbitmq_status = RABBITMQ_STATUS_READY;
  274. return Error_code::SUCCESS;
  275. }
  276. //反初始化 通信 模块。
  277. Error_manager Rabbitmq_base::rabbitmq_uninit()
  278. {
  279. LOG(INFO) << " ---Rabbitmq_base::rabbitmq_uninit() run--- "<< this;
  280. //终止list,防止 wait_and_pop 阻塞线程。
  281. m_send_list.termination_list();
  282. //杀死线程,强制退出
  283. if (mp_receive_analysis_thread)
  284. {
  285. m_receive_analysis_condition.kill_all();
  286. }
  287. if (mp_send_thread)
  288. {
  289. m_send_condition.kill_all();
  290. }
  291. if (mp_encapsulate_status_thread)
  292. {
  293. m_encapsulate_status_condition.kill_all();
  294. }
  295. //回收线程的资源
  296. if (mp_receive_analysis_thread)
  297. {
  298. mp_receive_analysis_thread->join();
  299. delete mp_receive_analysis_thread;
  300. mp_receive_analysis_thread = NULL;
  301. }
  302. if (mp_send_thread)
  303. {
  304. mp_send_thread->join();
  305. delete mp_send_thread;
  306. mp_send_thread = NULL;
  307. }
  308. if (mp_encapsulate_status_thread)
  309. {
  310. mp_encapsulate_status_thread->join();
  311. delete mp_encapsulate_status_thread;
  312. mp_encapsulate_status_thread = NULL;
  313. }
  314. //清空list
  315. m_send_list.clear_and_delete();
  316. if ( m_rabbitmq_status == RABBITMQ_STATUS_READY )
  317. {
  318. for (auto iter = m_channel_map.begin(); iter != m_channel_map.end(); ++iter)
  319. {
  320. amqp_channel_close(mp_connect, iter->first, AMQP_REPLY_SUCCESS);
  321. }
  322. amqp_connection_close(mp_connect, AMQP_REPLY_SUCCESS);
  323. amqp_destroy_connection(mp_connect);
  324. }
  325. m_rabbitmq_status = RABBITMQ_STATUS_UNKNOW;
  326. return Error_code::SUCCESS;
  327. }
  328. //重连, 快速uninit, init
  329. Error_manager Rabbitmq_base::rabbitmq_reconnnect()
  330. {
  331. //重连全程加锁,防止其他线程运行.
  332. std::unique_lock<std::mutex> lk(m_mutex);
  333. m_rabbitmq_status = RABBITMQ_STATUS_RECONNNECT;
  334. //断开连接
  335. for (auto iter = m_channel_map.begin(); iter != m_channel_map.end(); ++iter)
  336. {
  337. amqp_channel_close(mp_connect, iter->first, AMQP_REPLY_SUCCESS);
  338. }
  339. amqp_connection_close(mp_connect, AMQP_REPLY_SUCCESS);
  340. amqp_destroy_connection(mp_connect);
  341. //重新连接,线程不需要重启
  342. LOG(INFO) << " ---Rabbitmq_base::rabbitmq_reconnnect() run--- "<< this;
  343. int t_status=0; //状态
  344. amqp_rpc_reply_t t_reply; //reply答复结果
  345. Error_manager t_error;
  346. //amqp_new_connection 新建amqp的连接配置,里面只有连接状态参数
  347. // 返回amqp_connection_state_t_ *, 函数内部分配内存, amqp_destroy_connection()可以释放内存, 内存不为空则成功
  348. mp_connect = amqp_new_connection();
  349. if ( mp_connect == NULL )
  350. {
  351. return Error_manager(Error_code::RABBITMQ_AMQP_NEW_CONNECTION_ERROR, Error_level::MINOR_ERROR,
  352. "amqp_new_connection fun error ");
  353. }
  354. //amqp_tcp_socket_new 新建tcp_socket连接
  355. // 返回amqp_socket_t *, 函数内部分配内存, amqp_connection_close()可以释放内存, 内存不为空则成功
  356. mp_socket = amqp_tcp_socket_new(mp_connect);
  357. if ( mp_socket == NULL )
  358. {
  359. return Error_manager(Error_code::RABBITMQ_AMQP_TCP_SOCKET_NEW_ERROR, Error_level::MINOR_ERROR,
  360. "amqp_tcp_socket_new fun error ");
  361. }
  362. //载入外部参数
  363. if (m_rabbitmq_parameter_all.rabbitmq_parameters().has_ip() &&
  364. m_rabbitmq_parameter_all.rabbitmq_parameters().has_port() &&
  365. m_rabbitmq_parameter_all.rabbitmq_parameters().has_user() &&
  366. m_rabbitmq_parameter_all.rabbitmq_parameters().has_password() )
  367. {
  368. m_ip = m_rabbitmq_parameter_all.rabbitmq_parameters().ip();
  369. m_port = m_rabbitmq_parameter_all.rabbitmq_parameters().port();
  370. m_user = m_rabbitmq_parameter_all.rabbitmq_parameters().user();
  371. m_password = m_rabbitmq_parameter_all.rabbitmq_parameters().password();
  372. }
  373. else
  374. {
  375. return Error_manager(Error_code::RABBITMQ_PROTOBUF_LOSS_ERROR, Error_level::MINOR_ERROR,
  376. " rabbitmq_parameter_all.rabbitmq_parameters() The data is not complete ");
  377. }
  378. //amqp_socket_open 打开socket连接, 输入ip和port,
  379. // 成功返回AMQP_STATUS_OK = 0x0, 失败返回错误状态码, 详见 enum amqp_status_enum_
  380. //只需要设置配置服务器的ip和port, 不需要配置子节点客户端的ip和port, 在后面配置channel通道时,进行设置.
  381. t_status = amqp_socket_open(mp_socket, m_ip.c_str(), m_port);
  382. if ( t_status != AMQP_STATUS_OK )
  383. {
  384. return Error_manager(Error_code::RABBITMQ_AMQP_SOCKET_OPEN_ERROR, Error_level::MINOR_ERROR,
  385. amqp_error_to_string(t_status, "amqp_socket_open").c_str() );
  386. }
  387. //amqp_login() 登录代理服务器,
  388. //输入 连接参数结构体 amqp_connection_state_t,
  389. //输入 连接地址, 前面 amqp_socket_open() 已经输入了,这里默认写"/"
  390. //输入 连接通道最大值, 默认值0表示没有限制
  391. //输入 连接帧率最大值, 默认值是131072 (128KB)
  392. //输入 心跳帧之间的秒数, 默认值0禁用心跳
  393. //输入 身份验证模式, AMQP_SASL_METHOD_PLAIN, 追加用户名和密码
  394. // AMQP_SASL_METHOD_EXTERNAL, 追加身份证
  395. //返回 结果的结构体 amqp_rpc_reply_t
  396. // amqp_response_type_enum reply_type 登录成功是 AMQP_RESPONSE_NORMAL
  397. // 失败:如果是 reply_type == AMQP_RESPONSE_SERVER_EXCEPTION, 服务器连接错误, 错误信息在 amqp_method_t reply
  398. // 失败:如果是 reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION, 库函数错误, 错误信息在 int library_error
  399. t_reply = amqp_login(mp_connect, "/", 0, 131072, 0,
  400. AMQP_SASL_METHOD_PLAIN, m_user.c_str(), m_password.c_str());
  401. if ( t_reply.reply_type != AMQP_RESPONSE_NORMAL )
  402. {
  403. return Error_manager(Error_code::RABBITMQ_AMQP_LOGIN_ERROR, Error_level::MINOR_ERROR,
  404. amqp_error_to_string(t_reply, "amqp_login").c_str() );
  405. }
  406. //清除channel_map, 通道的缓存,防止重复开启, (channel允许重复使用, 但是不能重复初始化)
  407. m_channel_map.clear();
  408. //创建通道队列消费者, (交换机和永久队列不在代码里创建,请在服务器上手动创建)
  409. t_error = rabbitmq_new_channel_queue_consume(m_rabbitmq_parameter_all);
  410. if ( t_error != Error_code::SUCCESS )
  411. {
  412. return t_error;
  413. }
  414. //不用重启线程
  415. return Error_code::SUCCESS;
  416. }
  417. //设置 自动封装状态的时间周期
  418. void Rabbitmq_base::set_encapsulate_status_cycle_time(unsigned int encapsulate_status_cycle_time)
  419. {
  420. m_encapsulate_status_cycle_time = encapsulate_status_cycle_time;
  421. }
  422. //设置回调函数check_msg_callback
  423. void Rabbitmq_base::set_check_msg_callback(Error_manager (*callback)(Rabbitmq_message* p_msg))
  424. {
  425. check_msg_callback = callback;
  426. }
  427. //设置回调函数check_executer_callback
  428. void Rabbitmq_base::set_check_executer_callback(Error_manager (*callback)(Rabbitmq_message* p_msg))
  429. {
  430. check_executer_callback = callback;
  431. }
  432. //设置回调函数execute_msg_callback
  433. void Rabbitmq_base::set_execute_msg_callback(Error_manager (*callback)(Rabbitmq_message* p_msg))
  434. {
  435. execute_msg_callback = callback;
  436. }
  437. //设置回调函数encapsulate_status_callback
  438. void Rabbitmq_base::set_encapsulate_status_callback(Error_manager (*callback)())
  439. {
  440. encapsulate_status_callback = callback;
  441. }
  442. //mp_receive_analysis_thread 接受解析 执行函数,
  443. void Rabbitmq_base::receive_analysis_thread()
  444. {
  445. LOG(INFO) << " Rabbitmq_base::receive_analysis_thread start "<< this;
  446. //通信接受线程, 负责接受socket消息, 并存入 m_receive_data_list
  447. while (m_receive_analysis_condition.is_alive())
  448. {
  449. //这里就不需要超时等待了, rabbitmq的接受函数可以配置等待超时....
  450. // m_receive_analysis_condition.wait_for_ex(std::chrono::microseconds(1));
  451. m_receive_analysis_condition.wait();
  452. if ( m_receive_analysis_condition.is_alive() )
  453. {
  454. std::this_thread::yield();
  455. amqp_rpc_reply_t t_reply; //运行结果
  456. amqp_envelope_t t_envelope; //数据包, 含有一些包裹属性和数据内容
  457. //接受消息等待超时,默认1000us, 当收到消息后,立刻通过阻塞,否则等待超时后通过阻塞
  458. struct timeval t_timeout; //超时时间, 默认1ms
  459. t_timeout.tv_sec = 0;
  460. t_timeout.tv_usec = 1000;
  461. {//这个大括号表示只对 recv 和 send 加锁, 不要因为后面的复杂逻辑影响通信效率
  462. std::unique_lock<std::mutex> lk(m_mutex);
  463. //允许释放连接参数状态的内存,
  464. // 因为这个连接是底层分配的内存,是全局的. 为了开启多个连接,就要重复使用
  465. //这里释放之后,其他代码就开启多线程开启新的连接了.
  466. amqp_maybe_release_buffers(mp_connect);
  467. //amqp_consume_message 接受消息, 阻塞函数,可以设置超时.
  468. //输入 amqp_connection_state_t state 连接状态参数的结构体
  469. //输入 amqp_envelope_t *envelope 接受数据包的指针, 成功接收到数据后,数据包会覆盖
  470. //输入 const struct timeval *timeout 超时时间, 防止阻塞. 传入NULL就是完全阻塞.
  471. //输入 int flags 未使用, 默认0
  472. //输入 amqp_connection_state_t state 连接状态参数的结构体
  473. //返回 状态结果的结构体 amqp_rpc_reply_t
  474. // amqp_response_type_enum reply_type 成功是 AMQP_RESPONSE_NORMAL
  475. // 失败:如果是 reply_type == AMQP_RESPONSE_SERVER_EXCEPTION, 服务器连接错误, 错误信息在 amqp_method_t reply
  476. // 失败:如果是 reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION, 库函数错误, 错误信息在 int library_error
  477. t_reply = amqp_consume_message(mp_connect, &t_envelope, &t_timeout, 0);
  478. }
  479. if ( AMQP_RESPONSE_NORMAL == t_reply.reply_type )//正常接受到消息
  480. {
  481. m_rabbitmq_status = RABBITMQ_STATUS_READY;
  482. //从t_envelope数据包里面提取信息
  483. std::string t_receive_string = std::string((char*)t_envelope.message.body.bytes, t_envelope.message.body.len);
  484. int t_channel = t_envelope.channel;
  485. int t_delivery_tag = t_envelope.delivery_tag;
  486. std::string t_exchange_name = std::string((char*)t_envelope.exchange.bytes, t_envelope.exchange.len);
  487. std::string t_routing_key = std::string((char*)t_envelope.routing_key.bytes, t_envelope.routing_key.len);
  488. //如果这里接受到了消息, 在这提前解析消息最前面的Base_msg (消息公共内容), 用于后续的check
  489. message::Base_msg t_base_msg;
  490. // if( t_base_msg.ParseFromString(t_receive_string) )
  491. //删除 message::Base_msg 里面的 message::Base_info的机制,完全依赖服务器来分发消息
  492. if( true )
  493. {
  494. //第一次解析之后转化为, Communication_message, 自定义的通信消息格式
  495. Rabbitmq_message t_rabbitmq_message;
  496. t_rabbitmq_message.reset(t_base_msg.base_info(), t_receive_string, t_channel, t_delivery_tag, t_exchange_name, t_routing_key);
  497. //检查消息是否有效, 主要检查消息类型和接受者, 判断这条消息是不是给我的.
  498. if ( check_msg(&t_rabbitmq_message) == SUCCESS )
  499. {
  500. //这里直接就用当前线程进行处理,
  501. //检查消息是否可以被处理
  502. if ( check_executer(&t_rabbitmq_message) == SUCCESS )
  503. {
  504. //处理消息
  505. if ( execute_msg(&t_rabbitmq_message) == SUCCESS )
  506. {
  507. //...............
  508. }
  509. //else不做处理
  510. }
  511. //else不做处理
  512. }
  513. //else不做处理
  514. }
  515. //else解析失败, 就当做什么也没发生, 认为接收消息无效,
  516. else
  517. {
  518. std::cout << " huli test :::: " << " t_receive_string = " << t_receive_string << std::endl;
  519. if ( t_channel == 401 )
  520. {
  521. amqp_basic_ack(mp_connect, t_channel, t_delivery_tag, 0);
  522. }
  523. }
  524. //amqp_destroy_envelope 销毁数据包, 只有接受成功, t_envelope才有内存
  525. amqp_destroy_envelope(&t_envelope);
  526. }
  527. else//没有接受到消息
  528. {
  529. //超时报错,不做处理, continue
  530. //注注注注注意了, 没有收到消息会超时报错, res.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION, res.library_error = -13, (-0x000D request timed out)
  531. if (t_reply.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION && t_reply.library_error == -13)
  532. {
  533. m_rabbitmq_status = RABBITMQ_STATUS_READY;
  534. continue;
  535. }
  536. else//其他报错,特殊处理
  537. {
  538. //need
  539. std::string error_description = amqp_error_to_string(t_reply, "amqp_consume_message");
  540. std::cout << " huli test 123123123:::: " << " error_description = " << error_description << std::endl;
  541. // return Error_manager(Error_code::RABBITMQ_AMQP_CONSUME_MESSAGE_ERROR, Error_level::MINOR_ERROR,
  542. // amqp_error_to_string(t_reply, "amqp_consume_message") );
  543. //重启
  544. rabbitmq_reconnnect();
  545. }
  546. }
  547. }
  548. }
  549. LOG(INFO) << " Rabbitmq_base::receive_analysis_thread end "<< this;
  550. return;
  551. }
  552. //检查消息是否有效, 主要检查消息类型和接受者, 判断这条消息是不是给我的., 需要子类重载
  553. Error_manager Rabbitmq_base::check_msg(Rabbitmq_message* p_msg)
  554. {
  555. if ( check_msg_callback != NULL )
  556. {
  557. return check_msg_callback(p_msg);
  558. }
  559. return Error_code::SUCCESS;
  560. }
  561. //检查执行者的状态, 判断能否处理这条消息, 需要子类重载
  562. Error_manager Rabbitmq_base::check_executer(Rabbitmq_message* p_msg)
  563. {
  564. if ( check_executer_callback != NULL )
  565. {
  566. return check_executer_callback(p_msg);
  567. }
  568. return Error_code::SUCCESS;
  569. }
  570. //处理消息, 需要子类重载
  571. Error_manager Rabbitmq_base::execute_msg(Rabbitmq_message* p_msg)
  572. {
  573. if ( execute_msg_callback != NULL )
  574. {
  575. return execute_msg_callback(p_msg);
  576. }
  577. else
  578. {
  579. //需要子类重载
  580. std::cout << " huli test :::: " << " execute_msg Rabbitmq_message = " << p_msg->get_message_buf() << std::endl;
  581. //如果是请求消息,那么在子节点继承的时候一定要记得调用
  582. //配置rabbitmq.proto时, 如果consume_no_ack == 0 , 一定要手动调用 amqp_basic_ack
  583. int consume_no_ack = 1;
  584. if(consume_no_ack == 0 || p_msg->m_channel == 401)
  585. {
  586. //amqp_basic_ack 确认消息, 通知服务器队列手动删除消息.
  587. //输入 amqp_connection_state_t state 连接状态参数的结构体
  588. //输入 amqp_channel_t channel 连接通道的编号
  589. //输入 uint64_t delivery_tag 消息传递编号,
  590. //输入 amqp_boolean_t multiple 多个标记位, 默认0, 1表示删除1~delivery_tag的所有消息, 不删除大于delivery_tag的, 0表示只删除这一条
  591. int ack_result = amqp_basic_ack(mp_connect, p_msg->m_channel, p_msg->m_delivery_tag, 0);
  592. }
  593. }
  594. return Error_code::SUCCESS;
  595. }
  596. //ack_msg 处理完消息后, 手动确认消息, 通知服务器队列删除消息.
  597. //执行者在execute_msg里面可以调用这个函数, 或者回调也行.
  598. Error_manager Rabbitmq_base::ack_msg(Rabbitmq_message* p_msg)
  599. {
  600. //amqp_basic_ack 确认消息, 通知服务器队列手动删除消息.
  601. //输入 amqp_connection_state_t state 连接状态参数的结构体
  602. //输入 amqp_channel_t channel 连接通道的编号
  603. //输入 uint64_t delivery_tag 消息传递编号,
  604. //输入 amqp_boolean_t multiple 多个标记位, 默认0, 1表示删除1~delivery_tag的所有消息, 不删除大于delivery_tag的, 0表示只删除这一条
  605. int ack_result = amqp_basic_ack(mp_connect, p_msg->m_channel, p_msg->m_delivery_tag, 0);
  606. if ( ack_result != 0 )
  607. {
  608. return Error_manager(Error_code::RABBITMQ_AMQP_BASIC_ACK_ERROR, Error_level::MINOR_ERROR,
  609. amqp_error_to_string(ack_result, "amqp_basic_ack").c_str() );
  610. }
  611. return Error_code::SUCCESS;
  612. }
  613. //mp_send_thread 发送线程执行函数,
  614. void Rabbitmq_base::send_thread()
  615. {
  616. LOG(INFO) << " Rabbitmq_base::send_thread start "<< this;
  617. //通信发送线程, 负责巡检m_send_list, 并发送消息
  618. while (m_send_condition.is_alive())
  619. {
  620. m_send_condition.wait();
  621. if ( m_send_condition.is_alive() )
  622. {
  623. std::this_thread::yield();
  624. Rabbitmq_message* tp_msg = NULL;
  625. int t_result = 0;
  626. //这里 wait_and_pop 会使用链表内部的 m_data_cond 条件变量来控制等待,
  627. //封装线程使用push的时候, 会唤醒线程并通过等待, 此时 m_send_data_condition 是一直通过的.
  628. //如果需要退出, 那么就要 m_send_data_list.termination_list(); 和 m_send_data_condition.kill_all();
  629. bool is_pop = m_send_list.wait_and_pop(tp_msg);
  630. if ( is_pop )
  631. {
  632. if ( tp_msg != NULL )
  633. {
  634. //amqp_basic_properties_t 消息数据的基本属性,里面有15个成员.
  635. amqp_basic_properties_t props;
  636. //判断是否要设置发送消息的超时时间, 如果配置10秒,超时后,服务器会自动删除消息
  637. if ( tp_msg->m_timeout_ms == std::chrono::milliseconds(0) )
  638. {
  639. //amqp_flags_t _flags 一个uint32_t, 按位 表示这15个属性的修改开关.
  640. //例如: _flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG = 0b 1001 0000 0000 0000;
  641. //就表示 content-type 和 delivery-mode 是有效属性. 接下来的设置就会生效.
  642. props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG;
  643. //amqp_bytes_t content_type 消息数据的类型 "text/plain"是 普通文本格式
  644. //注意了,需要使用 amqp_cstring_bytes() 将char*转为amqp_bytes_t(自定义的字符串, 类似于std::string)
  645. props.content_type = amqp_cstring_bytes("text/plain");
  646. //uint8_t delivery_mode 配送模式 2表示持续发送模式
  647. props.delivery_mode = AMQP_DELIVERY_PERSISTENT;
  648. }
  649. else
  650. {
  651. //amqp_flags_t _flags 一个uint32_t, 按位 表示这15个属性的修改开关.
  652. //例如: _flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG = 0b 1001 0000 0000 0000;
  653. //就表示 content-type 和 delivery-mode 是有效属性. 接下来的设置就会生效.
  654. props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG | AMQP_BASIC_EXPIRATION_FLAG;
  655. //amqp_bytes_t content_type 消息数据的类型 "text/plain"是 普通文本格式
  656. //注意了,需要使用 amqp_cstring_bytes() 将char*转为amqp_bytes_t(自定义的字符串, 类似于std::string)
  657. props.content_type = amqp_cstring_bytes("text/plain");
  658. //uint8_t delivery_mode 配送模式 2表示持续发送模式
  659. props.delivery_mode = AMQP_DELIVERY_PERSISTENT;
  660. char buf[256] = {0};
  661. sprintf(buf, "%d", (int)tp_msg->m_timeout_ms.count());
  662. props.expiration = amqp_cstring_bytes(buf);//超时, 单位ms;
  663. }
  664. {//这个大括号表示只对 recv 和 send 加锁, 不要因为后面的复杂逻辑影响通信效率
  665. std::unique_lock<std::mutex> lk(m_mutex);
  666. // std::cout << " huli test :::: " << " tp_msg->m_message_buf = " << tp_msg->m_message_buf << std::endl;
  667. //amqp_basic_publish() 发布消息给代理服务器, 在交换器上发布一个带有路由密钥的消息。交换机会根据路由密钥匹配,放到对应的队列里面
  668. //输入 amqp_connection_state_t state 连接状态参数的结构体
  669. //输入 amqp_channel_t channel 连接通道的编号
  670. //输入 amqp_bytes_t exchange 交换机模式字符串
  671. //输入 amqp_bytes_t routing_key 路由密钥字符串, 交换机的判断规则. 发送端的 routingkey 和 接收端的 bindingkey 需要保持一致
  672. //输入 amqp_boolean_t mandatory 强制服务器必须通过路由密钥才能存到队列, 默认为0
  673. //输入 amqp_boolean_t immediate 表示服务器必须立刻转发消息给接受者, 默认为0
  674. //输入 struct amqp_basic_properties_t_ const *properties 消息数据的基本属性
  675. //输入 amqp_bytes_t body 消息数据内容
  676. //返回错误码 成功返回AMQP_STATUS_OK = 0x0, 失败返回错误状态码, 详见 enum amqp_status_enum_
  677. //注注注注注意了::amqp_basic_publish()是异步通信,
  678. // return AMQP_STATUS_OK 也只是表示消息成功发送到服务器. 无法确认 接收端是否正常接受消息
  679. t_result = amqp_basic_publish(mp_connect, tp_msg->m_channel,
  680. amqp_cstring_bytes(tp_msg->m_exchange_name.c_str()),
  681. amqp_cstring_bytes(tp_msg->m_routing_key.c_str()), 0, 0,
  682. &props, amqp_cstring_bytes(tp_msg->m_message_buf.c_str()) );
  683. }
  684. if ( t_result == AMQP_STATUS_OK )
  685. {
  686. m_rabbitmq_status = RABBITMQ_STATUS_READY;
  687. delete(tp_msg);
  688. tp_msg = NULL;
  689. // std::string re = amqp_error_to_string(t_result, "amqp_basic_publish");
  690. // std::cout << " huli test :::: " << " re = " << re << std::endl;
  691. // return Error_manager(Error_code::RABBITMQ_AMQP_BASIC_PUBLISH_ERROR, Error_level::MINOR_ERROR,
  692. // amqp_error_to_string(t_result, "amqp_basic_publish") );
  693. }
  694. else
  695. {
  696. std::string re = amqp_error_to_string(t_result, "amqp_basic_publish");
  697. std::cout << " huli test :::: " << " re = " << re << std::endl;
  698. //重启
  699. m_rabbitmq_status = RABBITMQ_STATUS_RECONNNECT;
  700. m_send_list.push(tp_msg); //重新加入队列,下一次再发
  701. tp_msg = NULL;
  702. rabbitmq_reconnnect();
  703. }
  704. }
  705. }
  706. else
  707. {
  708. //没有取出, 那么应该就是 m_termination_flag 结束了
  709. // return Error_manager(Error_code::CONTAINER_IS_TERMINATE, Error_level::MINOR_ERROR,
  710. // " Communication_socket_base::send_data_thread() error ");
  711. }
  712. }
  713. }
  714. LOG(INFO) << " Rabbitmq_base::send_thread end "<< this;
  715. return;
  716. }
  717. //手动封装消息,需要手动写入参数channel,exchange_name,routing_key
  718. Error_manager Rabbitmq_base::encapsulate_msg(std::string message, int channel, std::string exchange_name, std::string routing_key, int timeout_ms=0)
  719. {
  720. if ( m_rabbitmq_status != RABBITMQ_STATUS_READY )
  721. {
  722. return Error_manager(Error_code::ERROR, Error_level::MINOR_ERROR,
  723. " m_rabbitmq_status error ");
  724. }
  725. Rabbitmq_message* tp_msg = new Rabbitmq_message(message, channel, exchange_name, routing_key, timeout_ms);
  726. bool is_push = m_send_list.push(tp_msg);
  727. if ( is_push == false )
  728. {
  729. delete(tp_msg);
  730. tp_msg = NULL;
  731. return Error_manager(Error_code::CONTAINER_IS_TERMINATE, Error_level::MINOR_ERROR,
  732. " Communication_socket_base::encapsulate_msg error ");
  733. }
  734. return Error_code::SUCCESS;
  735. }
  736. //手动封装消息,需要手动写入参数channel,exchange_name,routing_key
  737. Error_manager Rabbitmq_base::encapsulate_msg(Rabbitmq_message* p_msg)
  738. {
  739. Rabbitmq_message* tp_msg = new Rabbitmq_message(*p_msg);
  740. bool is_push = m_send_list.push(tp_msg);
  741. if ( is_push == false )
  742. {
  743. delete(tp_msg);
  744. tp_msg = NULL;
  745. return Error_manager(Error_code::CONTAINER_IS_TERMINATE, Error_level::MINOR_ERROR,
  746. " Communication_socket_base::encapsulate_msg error ");
  747. }
  748. return Error_code::SUCCESS;
  749. }
  750. //手动封装任务消息(请求和答复), 系统会使用rabbitmq.proto的配置参数,
  751. Error_manager Rabbitmq_base::encapsulate_task_msg(std::string message, int vector_index)
  752. {
  753. int channel = m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_request_vector(vector_index).channel();
  754. std::string exchange_name = m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_request_vector(vector_index).exchange_name();
  755. std::string routing_key = m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_request_vector(vector_index).routing_key();
  756. int timeout_ms = m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_request_vector(vector_index).timeout_ms();
  757. Rabbitmq_message* tp_msg = new Rabbitmq_message(message, channel, exchange_name, routing_key, timeout_ms);
  758. bool is_push = m_send_list.push(tp_msg);
  759. if ( is_push == false )
  760. {
  761. delete(tp_msg);
  762. tp_msg = NULL;
  763. return Error_manager(Error_code::CONTAINER_IS_TERMINATE, Error_level::MINOR_ERROR,
  764. " Communication_socket_base::encapsulate_msg error ");
  765. }
  766. return Error_code::SUCCESS;
  767. }
  768. //手动封装状态消息, 系统会使用rabbitmq.proto的配置参数,
  769. Error_manager Rabbitmq_base::encapsulate_status_msg(std::string message, int vector_index)
  770. {
  771. if(m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_status_vector_size() <= vector_index)
  772. {
  773. std::cout<<"msg vector size error: "<<m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_status_vector_size()<<std::endl;
  774. return Error_manager(Error_code::PARAMETER_ERROR, Error_level::MINOR_ERROR,
  775. (std::string(" Communication_socket_base::encapsulate_msg vector index limit ")
  776. +std::to_string(m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_status_vector_size())).c_str());
  777. }
  778. int channel = m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_status_vector(vector_index).channel();
  779. std::string exchange_name = m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_status_vector(vector_index).exchange_name();
  780. std::string routing_key = m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_status_vector(vector_index).routing_key();
  781. int timeout_ms = m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_status_vector(vector_index).timeout_ms();
  782. Rabbitmq_message* tp_msg = new Rabbitmq_message(message, channel, exchange_name, routing_key, timeout_ms);
  783. bool is_push = m_send_list.push(tp_msg);
  784. if ( is_push == false )
  785. {
  786. delete(tp_msg);
  787. tp_msg = NULL;
  788. return Error_manager(Error_code::CONTAINER_IS_TERMINATE, Error_level::MINOR_ERROR,
  789. " Communication_socket_base::encapsulate_msg error ");
  790. }
  791. return Error_code::SUCCESS;
  792. }
  793. //mp_encapsulate_stauts_thread 自动封装线程执行函数,
  794. void Rabbitmq_base::encapsulate_status_thread()
  795. {
  796. LOG(INFO) << " Rabbitmq_base::encapsulate_status_thread start "<< this;
  797. //通信封装线程, 负责定时封装消息, 并存入 m_send_data_list
  798. while (m_encapsulate_status_condition.is_alive())
  799. {
  800. bool t_pass_flag = m_encapsulate_status_condition.wait_for_millisecond(m_encapsulate_status_cycle_time);
  801. if ( m_encapsulate_status_condition.is_alive() )
  802. {
  803. std::this_thread::yield();
  804. //如果封装线程被主动唤醒, 那么就表示 需要主动发送消息,
  805. if ( t_pass_flag )
  806. {
  807. //主动发送消息,
  808. }
  809. //如果封装线程超时通过, 那么就定时封装心跳和状态信息
  810. else
  811. {
  812. //只有通信正常的时候,才封装发送状态消息
  813. if ( m_rabbitmq_status == RABBITMQ_STATUS_READY )
  814. {
  815. auto_encapsulate_status();
  816. }
  817. }
  818. }
  819. }
  820. LOG(INFO) << " Rabbitmq_base::encapsulate_status_thread end "<< this;
  821. return;
  822. }
  823. //定时封装发送消息, 一般为心跳和状态信息, 需要子类重载
  824. Error_manager Rabbitmq_base::auto_encapsulate_status()
  825. {
  826. if ( encapsulate_status_callback != NULL )
  827. {
  828. return encapsulate_status_callback();
  829. }
  830. return Error_code::SUCCESS;
  831. }
  832. //把rabbitmq的错误信息转化为string, amqp_status就是enum amqp_status_enum_, amqp_error_string2()函数可以把他翻译为string
  833. std::string Rabbitmq_base::amqp_error_to_string(int amqp_status)
  834. {
  835. char buf[256] = {0};
  836. sprintf(buf, "amqp_status = 0x%x, %s", amqp_status, amqp_error_string2(amqp_status));
  837. return buf;
  838. }
  839. //把rabbitmq的错误信息转化为string, amqp_status就是enum amqp_status_enum_, amqp_error_string2()函数可以把他翻译为string
  840. std::string Rabbitmq_base::amqp_error_to_string(int amqp_status, std::string amqp_fun_name)
  841. {
  842. char buf[256] = {0};
  843. sprintf(buf, "amqp_fun_name = %s, amqp_status = 0x%x, %s", amqp_fun_name.c_str(), amqp_status, amqp_error_string2(amqp_status));
  844. return buf;
  845. }
  846. //把rabbitmq的错误信息转化为string, amqp_rpc_reply_t就是amqp函数运行的结果
  847. std::string Rabbitmq_base::amqp_error_to_string(amqp_rpc_reply_t amqp_rpc_reply)
  848. {
  849. char buf[256] = {0};
  850. // amqp_response_type_enum reply_type 登录成功是 AMQP_RESPONSE_NORMAL
  851. // 失败:如果是 reply_type == AMQP_RESPONSE_SERVER_EXCEPTION, 服务器连接错误, 错误信息在 amqp_method_t reply
  852. // 失败:如果是 reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION, 库函数错误, 错误信息在 int library_error
  853. switch ( amqp_rpc_reply.reply_type )
  854. {
  855. case AMQP_RESPONSE_NORMAL:
  856. {
  857. sprintf(buf, "SUCCESS");
  858. break;
  859. }
  860. case AMQP_RESPONSE_NONE:
  861. {
  862. sprintf(buf, " reply_type = AMQP_RESPONSE_NONE " );
  863. break;
  864. }
  865. case AMQP_RESPONSE_LIBRARY_EXCEPTION:
  866. {
  867. sprintf(buf, " reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION, library_error = %s, ",amqp_error_string2(amqp_rpc_reply.library_error) );
  868. break;
  869. }
  870. case AMQP_RESPONSE_SERVER_EXCEPTION:
  871. {
  872. if ( amqp_rpc_reply.reply.id == AMQP_CONNECTION_CLOSE_METHOD )
  873. {
  874. amqp_connection_close_t * p_decoded = (amqp_connection_close_t *)amqp_rpc_reply.reply.decoded;
  875. sprintf(buf, " reply.id = AMQP_CONNECTION_CLOSE_METHOD, reply = %u, %.*s ",
  876. p_decoded->reply_code, (int)p_decoded->reply_text.len, (char *)p_decoded->reply_text.bytes);
  877. }
  878. else if ( amqp_rpc_reply.reply.id == AMQP_CHANNEL_CLOSE_METHOD )
  879. {
  880. amqp_channel_close_t * p_decoded = (amqp_channel_close_t *)amqp_rpc_reply.reply.decoded;
  881. sprintf(buf, " reply.id = AMQP_CHANNEL_CLOSE_METHOD, reply = %u, %.*s ",
  882. p_decoded->reply_code, (int)p_decoded->reply_text.len, (char *)p_decoded->reply_text.bytes);
  883. }
  884. else
  885. {
  886. sprintf(buf, " reply_type = AMQP_RESPONSE_SERVER_EXCEPTION " );
  887. }
  888. break;
  889. }
  890. default:
  891. {
  892. sprintf(buf, " reply_type = unknown, reply.id = 0x%08X, ",
  893. amqp_rpc_reply.reply.id );
  894. break;
  895. }
  896. }
  897. return buf;
  898. }
  899. //把rabbitmq的错误信息转化为string, amqp_rpc_reply_t就是amqp函数运行的结果
  900. std::string Rabbitmq_base::amqp_error_to_string(amqp_rpc_reply_t amqp_rpc_reply, std::string amqp_fun_name)
  901. {
  902. char buf[256] = {0};
  903. // amqp_response_type_enum reply_type 登录成功是 AMQP_RESPONSE_NORMAL
  904. // 失败:如果是 reply_type == AMQP_RESPONSE_SERVER_EXCEPTION, 服务器连接错误, 错误信息在 amqp_method_t reply
  905. // 失败:如果是 reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION, 库函数错误, 错误信息在 int library_error
  906. switch ( amqp_rpc_reply.reply_type )
  907. {
  908. case AMQP_RESPONSE_NORMAL:
  909. {
  910. sprintf(buf, "SUCCESS");
  911. break;
  912. }
  913. case AMQP_RESPONSE_NONE:
  914. {
  915. sprintf(buf, "amqp_fun_name = %s, reply_type = AMQP_RESPONSE_NONE ", amqp_fun_name.c_str() );
  916. break;
  917. }
  918. case AMQP_RESPONSE_LIBRARY_EXCEPTION:
  919. {
  920. // huli test 123123123:::: error_description = amqp_fun_name = amqp_consume_message, reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION, library_error = unexpected protocol state,
  921. sprintf(buf, "amqp_fun_name = %s, reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION, library_error = %s, ", amqp_fun_name.c_str(),amqp_error_string2(amqp_rpc_reply.library_error) );
  922. break;
  923. }
  924. case AMQP_RESPONSE_SERVER_EXCEPTION:
  925. {
  926. if ( amqp_rpc_reply.reply.id == AMQP_CONNECTION_CLOSE_METHOD )
  927. {
  928. amqp_connection_close_t * p_decoded = (amqp_connection_close_t *)amqp_rpc_reply.reply.decoded;
  929. sprintf(buf, "amqp_fun_name = %s, reply.id = AMQP_CONNECTION_CLOSE_METHOD, reply = %u, %.*s ",
  930. amqp_fun_name.c_str(), p_decoded->reply_code, (int)p_decoded->reply_text.len, (char *)p_decoded->reply_text.bytes);
  931. }
  932. else if ( amqp_rpc_reply.reply.id == AMQP_CHANNEL_CLOSE_METHOD )
  933. {
  934. amqp_channel_close_t * p_decoded = (amqp_channel_close_t *)amqp_rpc_reply.reply.decoded;
  935. sprintf(buf, "amqp_fun_name = %s, reply.id = AMQP_CHANNEL_CLOSE_METHOD, reply = %u, %.*s ",
  936. amqp_fun_name.c_str(), p_decoded->reply_code, (int)p_decoded->reply_text.len, (char *)p_decoded->reply_text.bytes);
  937. }
  938. else
  939. {
  940. sprintf(buf, "amqp_fun_name = %s, reply_type = AMQP_RESPONSE_SERVER_EXCEPTION ", amqp_fun_name.c_str() );
  941. }
  942. break;
  943. }
  944. default:
  945. {
  946. sprintf(buf, "amqp_fun_name = %s, reply_type = unknown, reply.id = 0x%08X, ",
  947. amqp_fun_name.c_str(),amqp_rpc_reply.reply.id );
  948. break;
  949. }
  950. }
  951. return buf;
  952. }