瀏覽代碼

添加基础代码

Jeston 1 年之前
父節點
當前提交
bd30e17c8d

+ 16 - 14
CMakeLists.txt

@@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.5)
 
 project(AllProject)
 
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
 if (NOT DEFINED CMAKE_BUILD_TYPE OR ${CMAKE_BUILD_TYPE} STREQUAL "Debug")
     add_definitions(-DETC_PATH="${CMAKE_SOURCE_DIR}/etc/")
 else ()
@@ -10,18 +12,17 @@ endif ()
 
 # 第三方库
 find_package(PkgConfig REQUIRED)
-pkg_check_modules(nanomsg REQUIRED nanomsg)
-pkg_check_modules(YAML_CPP REQUIRED yaml-cpp)
-find_path(YAML_CPP_INCLUDE_DIR
-        NAMES yaml_cpp.h
-        PATHS ${YAML_CPP_INCLUDE_DIRS})
-find_library(YAML_CPP_LIBRARY
-        NAMES YAML_CPP
-        PATHS ${YAML_CPP_LIBRARY_DIRS})
-if (NOT ${YAML_CPP_VERSION} VERSION_LESS "0.5")
-    add_definitions(-DHAVE_NEW_YAMLCPP)
-endif (NOT ${YAML_CPP_VERSION} VERSION_LESS "0.5")
-#add_subdirectory(thirdpart/rs_driver)
+# pkg_check_modules(YAML_CPP REQUIRED yaml-cpp)
+# find_path(YAML_CPP_INCLUDE_DIR
+#         NAMES yaml_cpp.h
+#         PATHS ${YAML_CPP_INCLUDE_DIRS})
+# find_library(YAML_CPP_LIBRARY
+#         NAMES YAML_CPP
+#         PATHS ${YAML_CPP_LIBRARY_DIRS})
+# if (NOT ${YAML_CPP_VERSION} VERSION_LESS "0.5")
+#     add_definitions(-DHAVE_NEW_YAMLCPP)
+# endif (NOT ${YAML_CPP_VERSION} VERSION_LESS "0.5")
+# add_subdirectory(thirdpart/rs_driver)
 
 # Don't search with REQUIRED as we can continue without gflags.
 find_package(gflags 2.2.0)
@@ -39,14 +40,15 @@ else (gflags_FOUND)
     message("-- Did not find Google Flags (gflags), Building without gflags.")
     update_cache_variable(GFLAGS OFF)
 endif (gflags_FOUND)
+find_package(Glog)
 
 find_package(PCL REQUIRED)
 find_package(Eigen3 REQUIRED)
-find_package(Ceres REQUIRED)
 find_package(OpenCV REQUIRED)
-#find_package(rs_driver REQUIRED)
 find_package(Protobuf REQUIRED)
 
+# execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/protoc.sh ${CMAKE_CURRENT_LIST_DIR})
+
 if (EXISTS "${CMAKE_SOURCE_DIR}/include/CMakeLists.txt")
     include_directories(${CMAKE_SOURCE_DIR}/include)
     add_subdirectory(${CMAKE_SOURCE_DIR}/include)

+ 12 - 2
include/CMakeLists.txt

@@ -1,14 +1,24 @@
 
 message("===== compile library =====")
+
+unset(ENABLE_LIBRARY_ERROR_CODE CACHE)
 OPTION(ENABLE_LIBRARY_ERROR_CODE "" ON)
+unset(ENABLE_LIBRARY_GOOGLE_LOG CACHE)
 OPTION(ENABLE_LIBRARY_GOOGLE_LOG "" ON)
+unset(ENABLE_LIBRARY_PCL CACHE)
 OPTION(ENABLE_LIBRARY_PCL "" ON)
-OPTION(ENABLE_LIBRARY_RABBITMQ "" OFF)
+unset(ENABLE_LIBRARY_RABBITMQ CACHE)
+OPTION(ENABLE_LIBRARY_RABBITMQ "" ON)
+unset(ENABLE_LIBRARY_THREAD CACHE)
 OPTION(ENABLE_LIBRARY_THREAD "" ON)
-OPTION(ENABLE_LIBRARY_PLC "" ON)
+unset(ENABLE_LIBRARY_PLC CACHE)
+OPTION(ENABLE_LIBRARY_PLC "" OFF)
+unset(ENABLE_LIBRARY_JSON CACHE)
 OPTION(ENABLE_LIBRARY_JSON "" ON)
+unset(ENABLE_LIBRARY_FILE CACHE)
 OPTION(ENABLE_LIBRARY_FILE "" ON)
 
+add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/message)
 message("==> ENABLE_LIBRARY_ERROR_CODE " ${ENABLE_LIBRARY_ERROR_CODE})
 if (ENABLE_LIBRARY_ERROR_CODE)
     add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/error_code)

+ 10 - 0
include/error_code/error_code.hpp

@@ -495,6 +495,8 @@ enum Error_code {
     SNAP7_ANALYSIS_TIME_OUT,                                    //解析超时,
     SNAP7_EXCUTER_IS_BUSY,                                        //处理器正忙, 请稍等
 
+    TOF3D_VZENSE_DEVICE_INIT_SUCCESS = 0x1501000,
+    TOF3D_VZENSE_DEVICE_INIT_FAILED,
 
 
 
@@ -910,6 +912,14 @@ public://外部接口函数
         }
     }
 
+    void compare_and_merge_up(const Error_manager &error) {
+
+    }
+    void compare_and_merge_down(const Error_manager &error) {
+
+    }
+
+
     //output:error_description_string     错误汇总的string
     void translate_error_to_string(std::string error_aggregate_string) {
         char t_string_array[255] = {0};

+ 27 - 0
include/message/CMakeLists.txt

@@ -0,0 +1,27 @@
+set(LIBRARY_NAME libmessage)
+
+unset(OPTION_ENABLE_TEST_CODE CACHE)
+option(OPTION_ENABLE_TEST_CODE "Whether enable test code." OFF)
+message("<=${LIBRARY_NAME}=> OPTION_ENABLE_TEST_CODE: " ${OPTION_ENABLE_TEST_CODE})
+
+# 获取当前目录下的所有源文件
+aux_source_directory(${CMAKE_CURRENT_LIST_DIR} GLOB_RECURSE)
+
+set(LIBRARY_SOURCE_LIST
+        ${GLOB_RECURSE}
+)
+
+set(LIBRARY_DEPEND_LIST)
+
+add_library(${LIBRARY_NAME} ${LIBRARY_SOURCE_LIST})
+target_link_libraries(${LIBRARY_NAME} PUBLIC ${LIBRARY_DEPEND_LIST})
+
+if (OPTION_ENABLE_TEST_CODE)
+    set(LIBRARY_TEST_NAME "${LIBRARY_NAME}_test")
+    set(LIBRARY_TEST_SOURCE_LIST
+            ${CMAKE_CURRENT_LIST_DIR}/test.h
+            ${CMAKE_CURRENT_LIST_DIR}/test.cpp
+    )
+    add_executable(${LIBRARY_TEST_NAME} ${LIBRARY_TEST_SOURCE_LIST})
+    target_link_libraries(${LIBRARY_TEST_NAME} ${LIBRARY_NAME} )
+endif ()

文件差異過大導致無法顯示
+ 6647 - 0
include/message/measure.pb.cc


文件差異過大導致無法顯示
+ 4621 - 0
include/message/measure.pb.h


+ 277 - 0
include/message/measure.proto

@@ -0,0 +1,277 @@
+syntax = "proto3";
+
+enum Range_status {
+    Range_correct = 0x0000;                 // 未超界
+    Range_front = 0x0001;                   //前超界
+    Range_back = 0x0002;                    //后超界
+    Range_left = 0x0004;                    // 左超界
+    Range_right = 0x0008;                   // 右超界
+    Range_bottom = 0x0010;                  //底盘超界
+    Range_top = 0x0020;                     // 车顶超界
+    Range_car_width = 0x0040;               // 车宽超界
+    Range_car_wheelbase = 0x0080;           // 轴距超界
+    Range_angle_anti_clock = 0x0100;        // 左(逆时针)旋转超界
+    Range_angle_clock = 0x0200;             // 右(顺时针)旋转超界
+    Range_steering_wheel_nozero = 0x0400;   // 方向盘未回正
+    Range_car_moving = 0x0800;              // 车辆移动为1,静止为0
+}
+
+enum MeasureStatu {
+    Measure_OK = 0;                 // 测量完成
+    Measure_Empty_Clouds = 1;       // 测量结果:测量区域数据为空
+    Measure_Failture = 2;           // 测量结果:测量区域数据无法检测出车辆
+    Measure_Border = 3;             // 测量结果:对于PLC, 车辆存在超界,具体超界状态对比Range_status
+    Measure_Terminal_Border = 4;    // 测量结果:对于终端, 车辆存在超界,具体超界状态对比Range_status
+    Lidar_Disconnect = 5;           // 测量雷达:失去连接
+
+    Measure_Statu_Max = 6;
+}
+
+/*测量信息*/
+message measure_info {
+    float cx=1;                                 // 车辆中心坐标x
+    float cy=2;                                 // 车辆中心坐标y
+    float theta=3;                              // 车身偏转角度(相对于y轴,左正右负)
+    float length=4;                             // 车身长度(厦门四个雷达,含有该值,楚天两个雷达,该值为0)
+    float width=5;                              // 车身宽度(左右两侧轮子最大宽度)
+    float height=6;                             // 车身高度
+    float wheelbase=7;                          // 车辆前后轴距
+    float front_theta=8;                        // 车辆前轮偏转角度
+    int32 border_statu=9;                       // 超界状态, 位运算
+    MeasureStatu ground_status=10;              // 测量状态,0=正常, 1=空, 2=测量失败, 3=超界, 4=终端超界, 5=雷达断连
+    int32 is_stop=11;                           // <是否可停> 1为可停,0为不可停
+    int32 motion_statu=12;                      // 运动状态,0=运动, 1=静止(只有三秒内都是静止才会写1,只要瞬间触发运动就会写0)
+    float move_distance=13;                     // 前进距离
+}
+
+/*分配的车位信息*/
+message parkspace_info{
+    int32 id=1;
+    int32 serial_id=2;    //排序id
+    int32 table_id=3;     //标签id
+    int32 unit_id=4;      //单元号
+    int32 floor=5;        //楼层号
+    int32 room_id=6;      //同层编号
+    float height=7;       //车高档位
+}
+
+//任务表单状态
+enum STATU{
+    eNormal=0;        // 正常
+    eWarning=1;       // 警告
+    eError=2;         // 错误
+    eCritical=3;      // 严重错误
+}
+
+//表单流程模式
+enum Table_process_mode
+{
+    PROCESS_NORMAL = 0;             // 0:正常模式, 检查节点会向收费系统发送请求,收费系统的答复 通过后,再向调度发送请求
+    PROCESS_ONLY_TO_DISPATCH = 1;   // 1:强制存取车,检查节点会向收费系统发送请求,忽略收费系统的答复,直接向调度发送请求。
+    PROCESS_ONLY_TO_PAY = 2;        // 2:虚拟存取车, 检查节点会向收费系统发送请求,忽略收费系统的答复。
+}
+
+/*
+表单执行状态
+ */
+message table_statu{
+    STATU execute_statu=1;                    // 执行状态
+    string statu_description=2;               // 状态描述
+    Table_process_mode table_process_mod=3;   // 表单流程模式
+}
+/*
+号牌信息
+ */
+message plate_number_info
+{
+    string plate_number = 1;        // 号牌
+    string plate_color = 2;         // 号牌颜色
+    string plate_type = 3;          // 号牌类型, 车辆类型
+    int32  plate_confidence = 4;    // 号牌可信度, 1-100 值越高可信度越高
+    string recognition_time = 5;    // 识别时间点, yyyyMMddHHmmss
+    string plate_full_image = 6;    // 号牌全景图, base64编码
+    string plate_clip_image = 7;    // 号牌特写图, base64编码
+}
+/*
+停车表单
+ */
+message park_table{
+    table_statu statu=1;                      //表单状态
+    int32 queue_id=2;                         //指令排队编号
+
+    string car_number=3;
+    int32 unit_id=4;
+    int32 terminal_id=5;
+    string primary_key=6;
+
+    measure_buffer entrance_measure_info=7;     // 入口测量信息
+    parkspace_info allocated_space_info=8;    // 分配的车位信息
+    measure_buffer actually_measure_info=9;     // 实际测量信息或者叫二次测量信息
+    parkspace_info actually_space_info=10;    // 实际停放的车位
+    int32 import_id =11;                      // 入口id, 1~2
+
+    plate_number_info car_number_info = 12;   // 车牌号信息
+}
+
+/*
+取车表单
+ */
+message pick_table{
+    table_statu statu=1;      // 表单状态
+    int32 queue_id=2;         // 指令排队编号
+
+    string car_number=3;
+    int32 unit_id=4;
+    int32 terminal_id=5;
+    string primary_key=6;
+
+    parkspace_info actually_space_info=7;     // 实际停放的车位信息
+
+    measure_buffer actually_measure_info=8;     // 存车时的实际测量信息(轴距)
+
+    int32 export_id=9;                        // 出口id, 3~4
+    bool  is_leaved=10;                       // 是否离开
+    plate_number_info car_number_info = 11;   // 车牌号信息
+}
+
+/*
+以下是状态消息
+ */
+
+/*
+单片机节点状态
+ */
+message out_mcpu_statu{     //数值+1后
+    int32 door_statu=1;       //外门状态       0无效, 1无效, 2开到位, 3 关到位, 4开关中, 5 故障
+    int32 outside_safety=2;    //是否有车      0无效, 1无车, 2有车
+}
+
+message in_mcpu_statu{      //数值+1后
+    int32 door_statu=1;       //外门状态       0无效, 1无效, 2开到位, 3 关到位, 4开关中, 5 故障
+    int32 back_io=2;          //后超界       0无效, 1后超界, 2正常
+    int32 is_occupy=3;        //是否有车      0无效, 1无车, 2有车
+    int32 heighth=4;          //车高状态      0无效, 1无效, 2小车, 3中车, 4大车, 5故障, 6故障
+}
+/*
+测量节点状态
+ */
+message measure_buffer{
+    measure_info measure_info_to_plc_forward=1;     //雷达数据给plc,正向
+    measure_info measure_info_to_plc_reverse=2;     //雷达数据给plc,反向
+    measure_info measure_info_to_terminal=3;        //雷达数据给终端,边界较小
+}
+
+//搬运器状态枚举
+enum CarrierStatu{
+    eIdle=0;
+    eBusy=1;
+    eFault=2;
+}
+
+
+
+
+/*
+//楚天调度入口汽车范围的修正信息
+message dispatch_region_info
+{
+    int32 terminal_id=1;                //入口终端编号, 1~6
+    float turnplate_angle_min=2;        //转盘角度最小值, 负值, 例如 -5度
+    float turnplate_angle_max=3;        //转盘角度最大值, 正值, 例如 +5度
+}
+
+//楚天搬运器状态消息
+message dispatch_node_statu{
+    CarrierStatu statu=1;
+    int32 idle_stop_floor=2;  //空闲时停留位置
+    park_table  running_pack_info=3;  //正在执行的停车表单
+    pick_table  running_pick_info=4;  //正在执行的取车表单
+
+    int32                                   unit_id = 5;                            //单元号, 1~3
+    int32                                   plc_heartbeat = 6;                      //plc心跳信息
+    int32                                   plc_status_info = 7;                    //plc状态的集合
+                                                                                            //0 bit, 手动模式
+                                                                                            //1 bit, 自动模式
+                                                                                            //2 bit, 自动运行中
+                                                                                            //3 bit, 复位
+                                                                                            //4 bit, 1号口可以进车
+                                                                                            //5 bit, 2号口可以进车
+                                                                                            //6 bit, 预留
+                                                                                            //7 bit, 预留
+    repeated dispatch_region_info           dispatch_region_info_vector = 8;        //调度入口汽车范围的修正信息
+}
+ */
+
+
+
+//plc出入口状态结构体
+message dispatch_plc_passway_status
+{
+    int32			car_height = 1;			            //车高 0=无车 1=小车 2=中车 3=大车 4=超高车
+    int32			outside_door_status = 2;	        //外门状态 0=无状态 1=开到位 2=关到位
+    int32			inside_door_status = 3;	            //内门状态 0=无状态 1=开到位 2=关到位
+    int32			comb_body_status = 4;	            //梳体状态 0=无状态 1=上到位 2=下到位, AB特有
+    float			turnplate_angle_min = 5;	        //转盘角度最小值, C特有, 负值, 例如 -5度
+    float			turnplate_angle_max = 6;	        //转盘角度最大值, C特有, 正值, 例如 +5度
+    int32			sensor_1 = 7;				        //传感器状态的集合1
+                                                        //0 bit, 地感 0=无车 1=有车
+                                                        //1 bit, 移动检测 0=运动 1=静止
+                                                        //2 bit, 动态超限 0=遮挡 1=正常
+                                                        //3 bit, 后超界 0=遮挡 1=正常
+                                                        //4 bit, 前超界 0=遮挡 1=正常
+                                                        //5 bit, 左超界 0=遮挡 1=正常
+                                                        //6 bit, 右超界 0=遮挡 1=正常
+                                                        //7 bit, 车高小车, 0=遮挡 1=正常,AB单元为1480, C单元为1780,
+    int32			sensor_2 = 8;				        //传感器状态的集合1
+                                                        //0 bit, 车高中车, 0=遮挡 1=正常,AB单元为1500, C单元为1800,
+                                                        //1 bit, 车高大车, 0=遮挡 1=正常,AB单元为2050, C单元为2050,
+                                                        //2 bit, 有车检测 0=无车 1=有车
+                                                        //3 bit, 车轮1检测 0=无车 1=有车, AB特有
+                                                        //4 bit, 车轮2检测 0=无车 1=有车, AB特有
+                                                        //5 bit, 预留
+                                                        //6 bit, 预留
+                                                        //7 bit, 预留
+    int32           plc_passway_enable=9;               //出入口 0=不可进车, 1=可进车, 2=维护不可进车, 3=维护可进车
+}
+
+//厦门搬运器状态消息
+message dispatch_node_statu{
+    CarrierStatu                            statu=1;
+    int32                                   idle_stop_floor=2;          //空闲时停留位置
+    park_table                              running_pack_info=3;        //正在执行的停车表单
+    pick_table                              running_pick_info=4;        //正在执行的取车表单
+    int32                                   unit_id = 5;                //单元号, 1~3
+
+    int32                                   plc_heartbeat = 6;                      //plc心跳信息
+    int32                                   plc_mode_status = 7;                    //plc状态的集合
+                                                                                    //0 bit, 手动模式, 维修模式
+                                                                                    //1 bit, 自动模式
+                                                                                    //2 bit, 自动运行中
+                                                                                    //3 bit, 复位
+                                                                                    //4 bit, 预留
+                                                                                    //5 bit, 预留
+                                                                                    //6 bit, 预留
+                                                                                    //7 bit, 预留
+    int32                                   plc_passway_status = 8;                 //plc 出入口状态
+                                                                                    //0 bit, 入口1 可进车
+                                                                                    //1 bit, 入口1 维护
+                                                                                    //2 bit, 入口2 可进车
+                                                                                    //3 bit, 入口2 维护
+                                                                                    //4 bit, 出口1 可出车
+                                                                                    //5 bit, 出口1 维护
+                                                                                    //6 bit, 出口2 可出车
+                                                                                    //7 bit, 出口2 维护
+    int32                                   plc_carrier_status = 9;                 //搬运器状态 0=故障 1=存车 2=取车 3=空闲 4=维护
+    int32                                   plc_inlet_1_status = 10;                //入口1 0=不可进车, 1=可进车, 2=维护不可进车, 3=维护可进车
+    int32                                   plc_inlet_2_status = 11;                //入口2 0=不可进车, 1=可进车, 2=维护不可进车, 3=维护可进车
+    int32                                   plc_outlet_3_status = 12;               //出口3 0=不可进车, 1=可进车, 2=维护不可进车, 3=维护可进车
+    int32                                   plc_outlet_4_status = 13;               //出口4 0=不可进车, 1=可进车, 2=维护不可进车, 3=维护可进车
+
+    repeated dispatch_plc_passway_status    dispatch_plc_passway_status_vector = 14; //plc出入口状态结构体,  数组下标0~1是入口, 数组下标2~3是出口
+
+}
+message terminal_node_statu{
+    int32 terminal_id = 1;
+    int32 import_id = 2;
+    string car_number = 3;
+}

文件差異過大導致無法顯示
+ 6647 - 0
include/message/message.pb.cc


文件差異過大導致無法顯示
+ 4621 - 0
include/message/message.pb.h


+ 277 - 0
include/message/message.proto

@@ -0,0 +1,277 @@
+syntax = "proto3";
+
+enum Range_status {
+    Range_correct = 0x0000;                 // 未超界
+    Range_front = 0x0001;                   //前超界
+    Range_back = 0x0002;                    //后超界
+    Range_left = 0x0004;                    // 左超界
+    Range_right = 0x0008;                   // 右超界
+    Range_bottom = 0x0010;                  //底盘超界
+    Range_top = 0x0020;                     // 车顶超界
+    Range_car_width = 0x0040;               // 车宽超界
+    Range_car_wheelbase = 0x0080;           // 轴距超界
+    Range_angle_anti_clock = 0x0100;        // 左(逆时针)旋转超界
+    Range_angle_clock = 0x0200;             // 右(顺时针)旋转超界
+    Range_steering_wheel_nozero = 0x0400;   // 方向盘未回正
+    Range_car_moving = 0x0800;              // 车辆移动为1,静止为0
+}
+
+enum MeasureStatu {
+    Measure_OK = 0;                 // 测量完成
+    Measure_Empty_Clouds = 1;       // 测量结果:测量区域数据为空
+    Measure_Failture = 2;           // 测量结果:测量区域数据无法检测出车辆
+    Measure_Border = 3;             // 测量结果:对于PLC, 车辆存在超界,具体超界状态对比Range_status
+    Measure_Terminal_Border = 4;    // 测量结果:对于终端, 车辆存在超界,具体超界状态对比Range_status
+    Lidar_Disconnect = 5;           // 测量雷达:失去连接
+
+    Measure_Statu_Max = 6;
+}
+
+/*测量信息*/
+message measure_info {
+    float cx=1;                                 // 车辆中心坐标x
+    float cy=2;                                 // 车辆中心坐标y
+    float theta=3;                              // 车身偏转角度(相对于y轴,左正右负)
+    float length=4;                             // 车身长度(厦门四个雷达,含有该值,楚天两个雷达,该值为0)
+    float width=5;                              // 车身宽度(左右两侧轮子最大宽度)
+    float height=6;                             // 车身高度
+    float wheelbase=7;                          // 车辆前后轴距
+    float front_theta=8;                        // 车辆前轮偏转角度
+    int32 border_statu=9;                       // 超界状态, 位运算
+    MeasureStatu ground_status=10;              // 测量状态,0=正常, 1=空, 2=测量失败, 3=超界, 4=终端超界, 5=雷达断连
+    int32 is_stop=11;                           // <是否可停> 1为可停,0为不可停
+    int32 motion_statu=12;                      // 运动状态,0=运动, 1=静止(只有三秒内都是静止才会写1,只要瞬间触发运动就会写0)
+    float move_distance=13;                     // 前进距离
+}
+
+/*分配的车位信息*/
+message parkspace_info{
+    int32 id=1;
+    int32 serial_id=2;    //排序id
+    int32 table_id=3;     //标签id
+    int32 unit_id=4;      //单元号
+    int32 floor=5;        //楼层号
+    int32 room_id=6;      //同层编号
+    float height=7;       //车高档位
+}
+
+//任务表单状态
+enum STATU{
+    eNormal=0;        // 正常
+    eWarning=1;       // 警告
+    eError=2;         // 错误
+    eCritical=3;      // 严重错误
+}
+
+//表单流程模式
+enum Table_process_mode
+{
+    PROCESS_NORMAL = 0;             // 0:正常模式, 检查节点会向收费系统发送请求,收费系统的答复 通过后,再向调度发送请求
+    PROCESS_ONLY_TO_DISPATCH = 1;   // 1:强制存取车,检查节点会向收费系统发送请求,忽略收费系统的答复,直接向调度发送请求。
+    PROCESS_ONLY_TO_PAY = 2;        // 2:虚拟存取车, 检查节点会向收费系统发送请求,忽略收费系统的答复。
+}
+
+/*
+表单执行状态
+ */
+message table_statu{
+    STATU execute_statu=1;                    // 执行状态
+    string statu_description=2;               // 状态描述
+    Table_process_mode table_process_mod=3;   // 表单流程模式
+}
+/*
+号牌信息
+ */
+message plate_number_info
+{
+    string plate_number = 1;        // 号牌
+    string plate_color = 2;         // 号牌颜色
+    string plate_type = 3;          // 号牌类型, 车辆类型
+    int32  plate_confidence = 4;    // 号牌可信度, 1-100 值越高可信度越高
+    string recognition_time = 5;    // 识别时间点, yyyyMMddHHmmss
+    string plate_full_image = 6;    // 号牌全景图, base64编码
+    string plate_clip_image = 7;    // 号牌特写图, base64编码
+}
+/*
+停车表单
+ */
+message park_table{
+    table_statu statu=1;                      //表单状态
+    int32 queue_id=2;                         //指令排队编号
+
+    string car_number=3;
+    int32 unit_id=4;
+    int32 terminal_id=5;
+    string primary_key=6;
+
+    measure_buffer entrance_measure_info=7;     // 入口测量信息
+    parkspace_info allocated_space_info=8;    // 分配的车位信息
+    measure_buffer actually_measure_info=9;     // 实际测量信息或者叫二次测量信息
+    parkspace_info actually_space_info=10;    // 实际停放的车位
+    int32 import_id =11;                      // 入口id, 1~2
+
+    plate_number_info car_number_info = 12;   // 车牌号信息
+}
+
+/*
+取车表单
+ */
+message pick_table{
+    table_statu statu=1;      // 表单状态
+    int32 queue_id=2;         // 指令排队编号
+
+    string car_number=3;
+    int32 unit_id=4;
+    int32 terminal_id=5;
+    string primary_key=6;
+
+    parkspace_info actually_space_info=7;     // 实际停放的车位信息
+
+    measure_buffer actually_measure_info=8;     // 存车时的实际测量信息(轴距)
+
+    int32 export_id=9;                        // 出口id, 3~4
+    bool  is_leaved=10;                       // 是否离开
+    plate_number_info car_number_info = 11;   // 车牌号信息
+}
+
+/*
+以下是状态消息
+ */
+
+/*
+单片机节点状态
+ */
+message out_mcpu_statu{     //数值+1后
+    int32 door_statu=1;       //外门状态       0无效, 1无效, 2开到位, 3 关到位, 4开关中, 5 故障
+    int32 outside_safety=2;    //是否有车      0无效, 1无车, 2有车
+}
+
+message in_mcpu_statu{      //数值+1后
+    int32 door_statu=1;       //外门状态       0无效, 1无效, 2开到位, 3 关到位, 4开关中, 5 故障
+    int32 back_io=2;          //后超界       0无效, 1后超界, 2正常
+    int32 is_occupy=3;        //是否有车      0无效, 1无车, 2有车
+    int32 heighth=4;          //车高状态      0无效, 1无效, 2小车, 3中车, 4大车, 5故障, 6故障
+}
+/*
+测量节点状态
+ */
+message measure_buffer{
+    measure_info measure_info_to_plc_forward=1;     //雷达数据给plc,正向
+    measure_info measure_info_to_plc_reverse=2;     //雷达数据给plc,反向
+    measure_info measure_info_to_terminal=3;        //雷达数据给终端,边界较小
+}
+
+//搬运器状态枚举
+enum CarrierStatu{
+    eIdle=0;
+    eBusy=1;
+    eFault=2;
+}
+
+
+
+
+/*
+//楚天调度入口汽车范围的修正信息
+message dispatch_region_info
+{
+    int32 terminal_id=1;                //入口终端编号, 1~6
+    float turnplate_angle_min=2;        //转盘角度最小值, 负值, 例如 -5度
+    float turnplate_angle_max=3;        //转盘角度最大值, 正值, 例如 +5度
+}
+
+//楚天搬运器状态消息
+message dispatch_node_statu{
+    CarrierStatu statu=1;
+    int32 idle_stop_floor=2;  //空闲时停留位置
+    park_table  running_pack_info=3;  //正在执行的停车表单
+    pick_table  running_pick_info=4;  //正在执行的取车表单
+
+    int32                                   unit_id = 5;                            //单元号, 1~3
+    int32                                   plc_heartbeat = 6;                      //plc心跳信息
+    int32                                   plc_status_info = 7;                    //plc状态的集合
+                                                                                            //0 bit, 手动模式
+                                                                                            //1 bit, 自动模式
+                                                                                            //2 bit, 自动运行中
+                                                                                            //3 bit, 复位
+                                                                                            //4 bit, 1号口可以进车
+                                                                                            //5 bit, 2号口可以进车
+                                                                                            //6 bit, 预留
+                                                                                            //7 bit, 预留
+    repeated dispatch_region_info           dispatch_region_info_vector = 8;        //调度入口汽车范围的修正信息
+}
+ */
+
+
+
+//plc出入口状态结构体
+message dispatch_plc_passway_status
+{
+    int32			car_height = 1;			            //车高 0=无车 1=小车 2=中车 3=大车 4=超高车
+    int32			outside_door_status = 2;	        //外门状态 0=无状态 1=开到位 2=关到位
+    int32			inside_door_status = 3;	            //内门状态 0=无状态 1=开到位 2=关到位
+    int32			comb_body_status = 4;	            //梳体状态 0=无状态 1=上到位 2=下到位, AB特有
+    float			turnplate_angle_min = 5;	        //转盘角度最小值, C特有, 负值, 例如 -5度
+    float			turnplate_angle_max = 6;	        //转盘角度最大值, C特有, 正值, 例如 +5度
+    int32			sensor_1 = 7;				        //传感器状态的集合1
+                                                        //0 bit, 地感 0=无车 1=有车
+                                                        //1 bit, 移动检测 0=运动 1=静止
+                                                        //2 bit, 动态超限 0=遮挡 1=正常
+                                                        //3 bit, 后超界 0=遮挡 1=正常
+                                                        //4 bit, 前超界 0=遮挡 1=正常
+                                                        //5 bit, 左超界 0=遮挡 1=正常
+                                                        //6 bit, 右超界 0=遮挡 1=正常
+                                                        //7 bit, 车高小车, 0=遮挡 1=正常,AB单元为1480, C单元为1780,
+    int32			sensor_2 = 8;				        //传感器状态的集合1
+                                                        //0 bit, 车高中车, 0=遮挡 1=正常,AB单元为1500, C单元为1800,
+                                                        //1 bit, 车高大车, 0=遮挡 1=正常,AB单元为2050, C单元为2050,
+                                                        //2 bit, 有车检测 0=无车 1=有车
+                                                        //3 bit, 车轮1检测 0=无车 1=有车, AB特有
+                                                        //4 bit, 车轮2检测 0=无车 1=有车, AB特有
+                                                        //5 bit, 预留
+                                                        //6 bit, 预留
+                                                        //7 bit, 预留
+    int32           plc_passway_enable=9;               //出入口 0=不可进车, 1=可进车, 2=维护不可进车, 3=维护可进车
+}
+
+//厦门搬运器状态消息
+message dispatch_node_statu{
+    CarrierStatu                            statu=1;
+    int32                                   idle_stop_floor=2;          //空闲时停留位置
+    park_table                              running_pack_info=3;        //正在执行的停车表单
+    pick_table                              running_pick_info=4;        //正在执行的取车表单
+    int32                                   unit_id = 5;                //单元号, 1~3
+
+    int32                                   plc_heartbeat = 6;                      //plc心跳信息
+    int32                                   plc_mode_status = 7;                    //plc状态的集合
+                                                                                    //0 bit, 手动模式, 维修模式
+                                                                                    //1 bit, 自动模式
+                                                                                    //2 bit, 自动运行中
+                                                                                    //3 bit, 复位
+                                                                                    //4 bit, 预留
+                                                                                    //5 bit, 预留
+                                                                                    //6 bit, 预留
+                                                                                    //7 bit, 预留
+    int32                                   plc_passway_status = 8;                 //plc 出入口状态
+                                                                                    //0 bit, 入口1 可进车
+                                                                                    //1 bit, 入口1 维护
+                                                                                    //2 bit, 入口2 可进车
+                                                                                    //3 bit, 入口2 维护
+                                                                                    //4 bit, 出口1 可出车
+                                                                                    //5 bit, 出口1 维护
+                                                                                    //6 bit, 出口2 可出车
+                                                                                    //7 bit, 出口2 维护
+    int32                                   plc_carrier_status = 9;                 //搬运器状态 0=故障 1=存车 2=取车 3=空闲 4=维护
+    int32                                   plc_inlet_1_status = 10;                //入口1 0=不可进车, 1=可进车, 2=维护不可进车, 3=维护可进车
+    int32                                   plc_inlet_2_status = 11;                //入口2 0=不可进车, 1=可进车, 2=维护不可进车, 3=维护可进车
+    int32                                   plc_outlet_3_status = 12;               //出口3 0=不可进车, 1=可进车, 2=维护不可进车, 3=维护可进车
+    int32                                   plc_outlet_4_status = 13;               //出口4 0=不可进车, 1=可进车, 2=维护不可进车, 3=维护可进车
+
+    repeated dispatch_plc_passway_status    dispatch_plc_passway_status_vector = 14; //plc出入口状态结构体,  数组下标0~1是入口, 数组下标2~3是出口
+
+}
+message terminal_node_statu{
+    int32 terminal_id = 1;
+    int32 import_id = 2;
+    string car_number = 3;
+}

文件差異過大導致無法顯示
+ 4091 - 0
include/message/message_base.pb.cc


文件差異過大導致無法顯示
+ 3167 - 0
include/message/message_base.pb.h


+ 309 - 0
include/message/message_base.proto

@@ -0,0 +1,309 @@
+syntax = "proto2";
+package message;
+
+//消息类型定义;每个在网络上传输的消息必须含有这个属性
+enum Message_type
+{
+    eBase_msg=0x00;
+    eCommand_msg=0x01;                      //指令消息
+
+
+    eLocate_status_msg=0x11;                //定位模块状态消息
+    eLocate_request_msg=0x12;               //定位请求消息
+    eLocate_response_msg=0x13;              //定位反馈消息
+
+    eLocate_sift_request_msg = 0x14;            //预测算法请求消息
+    eLocate_sift_response_msg = 0x15;           //预测算法反馈消息
+
+    eDispatch_status_msg=0x21;                //调度模块硬件状态消息
+    eDispatch_request_msg=0x22;              //请求调度消息
+    eDispatch_response_msg=0x23;             //调度结果反馈消息
+
+    eParkspace_allocation_status_msg=0x31;  //车位分配模块状态消息,包括车位信息
+    eParkspace_allocation_request_msg=0x32; //请求分配车位消息
+    eParkspace_allocation_response_msg=0x33;//分配车位结果反馈消息
+    eParkspace_search_request_msg = 0x34;		//查询车位请求消息
+    eParkspace_search_response_msg = 0x35;		//查询车位反馈消息
+    eParkspace_release_request_msg = 0x36;		//释放车位请求消息
+    eParkspace_release_response_msg = 0x37;		//释放车位反馈消息
+    eParkspace_force_update_request_msg = 0x38;	//手动修改车位消息
+    eParkspace_force_update_response_msg = 0x39;//手动修改车位反馈消息
+    eParkspace_confirm_alloc_request_msg = 0x3A;//确认分配车位请求消息
+    eParkspace_confirm_alloc_response_msg = 0x3B;//确认分配车位反馈消息
+    eParkspace_allocation_data_msg = 0x3C;     //车位分配模块车位数据消息
+    eParkspace_allocation_data_response_msg =0x3D;//车位数据反馈消息
+    eParkspace_manual_search_request_msg = 0x3E;	//手动查询车位请求消息
+    eParkspace_manual_search_response_msg = 0x3F;//手动查询车位反馈消息
+
+    eStore_command_request_msg=0x41;        //终端停车请求消息
+    eStore_command_response_msg=0x42;       //停车请求反馈消息
+    ePickup_command_request_msg=0x43;       //取车请求消息
+    ePickup_command_response_msg=0x44;       //取车请求反馈消息
+
+    eTerminal_status_msg = 0x50;	 //终端状态消息
+
+    eStoring_process_statu_msg=0x90;        //停车指令进度条消息
+    ePicking_process_statu_msg=0x91;        //取车指令进度消息
+
+
+    eCentral_controller_statu_msg=0xa0;     //中控系统状态消息
+
+
+    eEntrance_manual_operation_msg=0xb0;            //针对出入口状态操作的手动消息
+    eProcess_manual_operation_msg=0xb1;             //针对流程的手动消息
+
+    eNotify_request_msg=0xc0;               //取车等候区通知请求
+    eNotify_response_msg=0xc1;              //等候区反馈
+    eNotify_status_msg=0xc2;                //等候区通知节点状态
+
+    eUnNormalized_module_statu_msg = 0xd0; //非标节点状态
+
+    eDispatch_plan_request_msg          = 0xe0;     //调度总规划的请求(用于启动整个调度算法)(调度管理->调度算法)
+    eDispatch_plan_response_msg         = 0xe1;     //调度总规划的答复(调度算法->调度管理)
+    eDispatch_control_request_msg       = 0xe2;     //调度控制的任务请求(调度算法->调度管理)
+    eDispatch_control_response_msg      = 0xe3;     //调度控制的任务答复(调度管理->调度算法)
+    eDispatch_manager_status_msg        = 0xea;     //调度管理的设备状态消息(调度底下所有硬件设备状态的汇总)
+    eDispatch_manager_data_msg          = 0xeb;     //调度管理的设备详细的数据信息
+
+
+    eGround_detect_request_msg=0xf0;        //地面雷达测量请求消息
+    eGround_detect_response_msg=0xf1;       //地面雷达测量反馈消息
+    eGround_status_msg=0xf2;                //地面雷达状态消息
+
+}
+
+//通讯单元
+enum Communicator
+{
+    eEmpty=0x0000;
+    eMain=0x0001;    //主流程
+
+    eTerminor=0x0100;
+    //车位表
+    eParkspace=0x0200;
+    //测量单元
+    eMeasurer=0x0300;
+    //测量单元的服务器
+    eMeasurer_sift_server=0x0301;
+    //调度机构
+    eDispatch_manager=0x0400;
+    //调度机构
+    eDispatch_control=0x0401;
+    //...
+  //取车等候区通知节点
+    eNotify=0x0501;
+
+    //地面测量单元
+	eGround_measurer=0x0f00;
+}
+////base message 用于解析未知类型的消息
+message Base_info
+{
+    required Message_type               msg_type=1[default = eBase_msg];
+    optional int32                      timeout_ms=2[default = 0];
+    required Communicator               sender=3[default = eEmpty];                       //发送者
+    required Communicator               receiver=4[default = eEmpty];                     //接收者
+}
+
+// 事件,停车或者取车
+enum Process_type
+{
+    eStoring=1;
+    ePicking=2;
+}
+
+
+message Base_msg
+{
+    required Base_info                  base_info=1;
+}
+
+//错误等级,用来做故障处理
+enum Error_level
+{
+    NORMAL                = 0;      //    正常,没有错误,默认值0
+
+    NEGLIGIBLE_ERROR      = 1;      //    轻微故障;可忽略的故障,NEGLIGIBLE_ERROR
+
+    MINOR_ERROR           = 2;      //    一般故障,MINOR_ERROR
+
+    MAJOR_ERROR           = 3;      //    严重故障,MAJOR_ERROR
+
+    CRITICAL_ERROR        = 4;      //    致命故障,CRITICAL_ERROR
+
+}
+
+message Error_manager
+{
+    required int32                      error_code = 1[default = 0];
+    optional Error_level                error_level = 2[default = NORMAL];
+    optional string                     error_description = 3[default = ""];
+}
+
+//测量结果结构体
+message Locate_information
+{
+    optional float locate_x = 1[default = 0];				//整车的中心点x值; 四轮的中心
+    optional float locate_y = 2[default = 0];				//整车的中心点y值; 四轮的中心
+    optional float locate_angle = 3[default = 0];			//整车的旋转角; 四轮的旋转角
+    optional float locate_length = 4[default = 0];		    //整车的长度; 用于规避碰撞
+    optional float locate_width = 5[default = 0];			//整车的宽度; 用于规避碰撞
+    optional float locate_height = 6[default = 0];		    //整车的高度; 用于规避碰撞
+    optional float locate_wheel_base = 7[default = 0];	    //整车的轮距; 前后轮的距离; 用于机器人或agv的抓车
+    optional float locate_wheel_width = 8[default = 0];	    //整车的轮距; 左右轮的距离; 用于机器人或agv的抓车
+    optional bool locate_correct = 9[default = false];		    //整车的校准标记位
+
+    optional float locate_front_theta = 10[default = 0];	    //整车的前轮的旋转角
+    
+    optional float uniformed_car_x = 11;        //转角复位后,车辆中心点x
+    optional float uniformed_car_y = 12;        //转角复位后,车辆中心点y
+}
+
+//车辆基本信息
+message Car_info
+{
+    optional float                      car_length=1[default = 0];           //车长
+    optional float                      car_width=2[default = 0];            //车宽
+    optional float                      car_height=3[default = 0];           //车高
+    optional string                     license=4[default = ""];             //车辆凭证号(车牌号+唯一码)
+    optional string                     car_numberPlate = 5[default = ""];   //车牌号
+    optional float                      car_wheel_base = 6[default = 0];	 //整车的轮距; 前后轮的距离; 用于机器人或agv的抓车
+    optional float                      car_wheel_width = 7[default = 0];	 //整车的轮距; 左右轮的距离; 用于机器人或agv的抓车
+}
+
+//车位状态枚举
+enum Parkspace_status
+{
+    eParkspace_status_unknow    = 0;
+    eParkspace_empty            = 1;         //空闲,可分配
+    eParkspace_occupied         = 2;         //被占用,不可分配
+    eParkspace_reserved         = 3;         //被预约,预约车辆可分配
+    eParkspace_locked           = 4;         //临时锁定,不可分配
+    eParkspace_error            = 5;         //车位机械结构或硬件故障
+}
+
+//车位朝向, 小号朝前朝南, 大号朝后朝北
+enum Direction
+{
+    eDirection_unknow = 0;
+    eForward = 1;                   //小号朝前朝南
+    eBackward = 2;                  //大号朝后朝北
+}
+
+//车位分配路线(根据中跑车的路线来定)
+enum Parkspace_path
+{
+	UNKNOW_PATH = 0;
+    OPTIMAL_PATH = 1;
+    LEFT_PATH = 2;
+    RIGHT_PATH = 3;
+    TEMPORARY_CACHE_PATH = 4;
+}
+
+//车位类型
+enum Parkspace_type
+{
+    UNKNOW_PARKSPACE_TYPE = 0;
+    MIN_PARKINGSPACE = 1;//小车位
+    MID_PARKINGSPACE = 2;//中车位
+    BIG_PARKINGSPACE = 3;//大车位
+}
+
+//汽车类型
+enum Car_type
+{
+    UNKNOW_CAR_TYPE = 0;
+    MIN_CAR = 1;//小车
+    MID_CAR = 2;//中车
+    BIG_CAR = 3;//大车
+}
+
+//单个车位基本信息与状态信息,车位信息以及车位上的车辆信息
+message Parkspace_info
+{
+    optional int32              parkingspace_index_id = 1;            //车位ID
+    optional Parkspace_type     parkingspace_type = 2;                //车位类型
+    optional int32              parkingspace_unit_id = 3;            //车位单元号
+    optional int32              parkingspace_label_id = 4;            //车位单元内部ID
+    optional int32              parkingspace_room_id = 5;             //同层编号
+    optional Direction          parkingspace_direction = 6;           //前后
+    optional int32              parkingspace_floor_id = 7;            //楼层
+    optional float              parkingspace_width = 8;               //车位宽
+    optional float              parkingspace_height = 9;              //车位高
+    optional Parkspace_status   parkingspace_status = 10;              //车位当前状态
+    optional Car_info           car_info = 11;                        //车辆信息
+    optional string             entry_time = 12;                      //入场时间
+    optional string             leave_time = 13;                      //离场时间
+
+
+    optional Parkspace_path     parkspace_path = 14;            // 车位分配路线
+    optional float              path_estimate_time = 15;        //车位分配路线 time(s)
+    optional Parkspace_status   parkspace_status_target = 16;     //车位目标状态
+
+    optional Car_type           car_type = 17;                        //车辆类型
+
+
+}
+
+/*
+*流程中的步骤类型, 例如:停车流程包含5个步骤 , 分配车位-测量-检验结果-搬运-更新车位表
+*/
+enum Step_type
+{
+    eAlloc_step=0;
+    eMeasure_step=1;
+    eCompare_step=2;
+    eDispatch_step=3;
+    eConfirm_step=4;
+
+    eSearch_step=5;        //查询数据库
+    eWait_step=6;             //等待车辆离开
+    eRelease_step=7;          //释放车位
+
+    eComplete=8;              //完成
+
+    eBackConfirm_step=9;
+    eBack_compare_step=10;
+    eBackMeasure_step=11;
+    eBackAlloc_step=12;
+
+    eBackWait_step=13;
+    eBackDispatch_step=14;
+    eBackSearch_step=15;
+
+    eBackComplete=16;
+}
+//步骤状态,每个步骤有四中可能状态 ,等待中-执行中-完成或者错误  四个状态
+enum Step_statu
+{
+    eWaiting=0;               //完成/空闲
+    eWorking=1;
+    eError=2;
+    eFinished=3;
+}
+
+//调度设备的类型
+enum Dispatch_device_type
+{
+    ROBOT_1                                 = 101;      //一号出口的专用机器手(只能负责1号出口的取车)(目前没有安装,暂时不考虑)
+    ROBOT_2                                 = 102;      //中间的大型机器手   (可以负责1~6号出入口的停车和取车)
+
+    CARRIER_1                               = 200;      //左侧0号电梯井的搬运器(升降电梯 中跑车 小跑车 三合一为搬运器)
+    CARRIER_2                               = 207;      //右侧7号电梯井的搬运器(升降电梯 中跑车 小跑车 三合一为搬运器)
+    CARRIER_3                               = 203;      //中间3楼的搬运器(中跑车 小跑车 二合一为搬运器)(没有电梯, 只能在3楼活动)
+
+    PASSAGEWAY_0                            = 300;      //0号出口(在左侧电梯井, 只能取车)(暂时不存在)
+    PASSAGEWAY_1                            = 301;      //1号出入口
+    PASSAGEWAY_2                            = 302;      //2号出入口
+    PASSAGEWAY_3                            = 303;      //3号出入口
+    PASSAGEWAY_4                            = 304;      //4号出入口
+    PASSAGEWAY_5                            = 305;      //5号出入口
+    PASSAGEWAY_6                            = 306;      //6号出入口
+    PASSAGEWAY_7                            = 307;      //7号出口(在右侧电梯井, 只能取车)
+}
+
+message Id_struct
+{
+    optional int32 terminal_id=1;   //终端ID
+    optional int32 unit_id=2;       //单元号
+}

+ 1 - 1
include/pcl/CMakeLists.txt

@@ -1,7 +1,7 @@
 set(LIBRARY_NAME libpcl)
 
 unset(OPTION_ENABLE_TEST_CODE CACHE)
-option(OPTION_ENABLE_TEST_CODE "Whether enable test code." ON)
+option(OPTION_ENABLE_TEST_CODE "Whether enable test code." OFF)
 message("<=${LIBRARY_NAME}=> OPTION_ENABLE_TEST_CODE: " ${OPTION_ENABLE_TEST_CODE})
 
 if (NOT ENABLE_LIBRARY_GOOGLE_LOG)

+ 28 - 3
include/rabbitmq/CMakeLists.txt

@@ -1,11 +1,36 @@
 set(LIBRARY_NAME librabbitmq)
 
-option(OPTION_ENABLE_TEST_CODE "Whether enable test code." ON)
+unset(OPTION_ENABLE_TEST_CODE CACHE)
+option(OPTION_ENABLE_TEST_CODE "Whether enable test code." OFF)
 message("<=${LIBRARY_NAME}=> test: " ${OPTION_ENABLE_TEST_CODE})
 
-set(LIBRARY_SOURCE_LIST)
+execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/protoc.sh ${CMAKE_CURRENT_LIST_DIR})
 
-set(LIBRARY_DEPEND_LIST)
+
+set(LIBRARY_SOURCE_LIST
+    ${CMAKE_CURRENT_LIST_DIR}/rabbitmq_base.h
+    ${CMAKE_CURRENT_LIST_DIR}/rabbitmq_base.cpp
+    ${CMAKE_CURRENT_LIST_DIR}/rabbitmq_message.h
+    ${CMAKE_CURRENT_LIST_DIR}/rabbitmq_message.cpp
+    ${CMAKE_CURRENT_LIST_DIR}/rabbitmq.pb.cc
+    ${CMAKE_CURRENT_LIST_DIR}/rabbitmq.pb.h
+)
+
+if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
+    set(Rabbitmq
+            /usr/lib/aarch64-linux-gnu/librabbitmq.a
+            )
+else()
+    set(Rabbitmq
+            /usr/local/lib/librabbitmq.a
+            )
+endif()
+
+set(LIBRARY_DEPEND_LIST
+    libthread
+    ${Rabbitmq}
+    ${PROTOBUF_LIBRARIES}
+)
 
 add_library(${LIBRARY_NAME} ${LIBRARY_SOURCE_LIST})
 target_link_libraries(${LIBRARY_NAME} PUBLIC ${LIBRARY_DEPEND_LIST})

+ 27 - 0
include/rabbitmq/executor_mq.hpp

@@ -0,0 +1,27 @@
+/*
+ * @brief 该模块用于接收命令并执行命令, 然后将执行结果发送回发送着.
+*/
+
+#pragma once
+#include "executor.hpp"
+#include "defines.hpp"
+
+class ExecutorRabbitmq: public Executor<ExecutorRabbitmq> {
+    friend class SingletonIter<ExecutorRabbitmq>;
+public:
+    Error_manager connect() {
+        return Error_code::SUCCESS;
+    }
+
+    ~ExecutorRabbitmq() override = default;
+private:
+
+protected:
+    ExecutorRabbitmq() = default;
+
+};
+
+
+
+
+

文件差異過大導致無法顯示
+ 1921 - 0
include/rabbitmq/rabbitmq.pb.cc


文件差異過大導致無法顯示
+ 1661 - 0
include/rabbitmq/rabbitmq.pb.h


+ 67 - 0
include/rabbitmq/rabbitmq.proto

@@ -0,0 +1,67 @@
+syntax = "proto2";
+package Rabbitmq_proto;
+
+//Rabbitmq 配置的通道,队列和消费者,
+//注:目前规定
+//接受请求消息:同一子节点所有的请求消息写同一个channel通道编号,queue_durable = 1, queue_auto_delete = 0, consume_no_ack = 0,
+//接受状态消息:同一子节点所有的状态消息写同一个channel通道编号,queue_durable = 0, queue_auto_delete = 1, consume_no_ack = 1,
+message Rabbitmq_channel_queue_consume
+{
+    optional int32 channel = 1;                             //连接通道,必写, 可以相同, 不同的消息队列可以共用同一个连接通道,
+                                                            //配合 amqp_basic_qos 和 amqp_basic_ack , 来阻塞这个通道的接受消息
+                                                            //请求消息和状态消息必须分别写不同的通道,例如所有的请求都可以写12, 所有的状态都可以写34
+    optional string exchange_name = 2;                      //交换机名称,必写, 可以相同, 不同的消息队列可以共用同一个交换机,
+                                                            //配合 routingkey 和 bindingkey , 来分配消息到合适的队列
+
+    //发送队列专属
+    optional string routing_key = 3;                        //发送端的路由键, 交换机分配消息的判断条件
+    optional int32 timeout_ms = 4;                          //发送超时时间, 单位ms, 服务器会自动删除超时的消息, 如果写0,那么就没有超时删除
+
+    //接受队列专属
+    optional string binding_key = 5;                        //接受端的绑定键, 交换机分配消息的判断条件
+    optional string queue_name = 6;                         //队列名称,必写, 不能相同
+    optional int32 queue_passive = 7[default = 0];          //是否被动,默认0
+    optional int32 queue_durable = 8;                       //是否持久,必写, 节点代码可以创建临时队列(所有权归节点), 服务器手动创建永久队列(所有权归服务器)
+                                              		        //		1表示永久队列,当节点死掉,队列在服务器保留,仍然可以接受数据,节点上线后,可以接受掉线期间的所有数据
+                                              		        //		0表示临时队列,当节点死掉,队列消失,不再接受数据,直到下次恢复正常
+    optional int32 queue_exclusive = 9[default = 0];        //是否独立,默认0
+    optional int32 queue_auto_delete = 10[default = 0];      //是否自动删除, 固定写0,
+                                                            //1表示消息被消费者接受后,就自动删除消息, 当接收端断连后,队列也会删除,
+                                                            //0表示消息被消费者接受后,不会自动删除消息, 需要手动ack才会删除消息, 队列不会删除
+                                                            //一般情况下设为0,然后让接受者手动删除.
+     optional int32 queue_meassage_ttl = 11[default = 0];   //队列配置的扩展参数, x-message-ttl 队列接受消息 的超时时间 (单位毫秒)
+                                                            //默认写0, 不配置超时, 一般在状态消息的临时队列写入1000ms
+
+
+    optional string consume_name = 12;                       //消费者名称,必写, 不能相同
+    optional int32 consume_no_local = 13[default = 0];      //是否非本地, 默认0,表示本地
+    optional int32 consume_no_ack = 14[default = 0];        //是否确认应答,默认0,表示接收后需要应答
+                                                            //请求消息必须写0, 必须应答之后才能接受下一条
+                                                            //状态消息必须写1, 可以无限循环接受,收到的瞬间,服务器就会删除这一条消息
+    optional int32 consume_exclusive = 15;                  //是否独立,默认0
+
+}
+
+
+
+//Rabbitmq 配置参数
+message Rabbitmq_parameter
+{
+    optional string ip = 1;             //服务器ip地址, 不带端口
+    optional int32 port = 2;            //端口,默认5672
+    optional string user = 3;           //用户名, 默认guest
+    optional string password = 4;       //密码, 默认guest
+
+    repeated Rabbitmq_channel_queue_consume rabbitmq_reciever_vector= 5;                //Rabbitmq 接受的通道,队列和消费者, 多个
+    repeated Rabbitmq_channel_queue_consume rabbitmq_sender_request_vector= 6;         //Rabbitmq 发送请求的通道
+    repeated Rabbitmq_channel_queue_consume rabbitmq_sender_status_vector= 7;          //Rabbitmq 发送状态的通道
+    //注:rabbitmq的接受是以队列为目标的, 可以同时接受多个队列的消息.
+    //注:rabbitmq的发送是以交换机为目标的,我们发送到交换机后,由交换机按照规则,去分配到下面的队列里面
+
+}
+
+//Rabbitmq 配置参数 总配置
+message Rabbitmq_parameter_all
+{
+    optional Rabbitmq_parameter        rabbitmq_parameters=1;
+}

+ 981 - 0
include/rabbitmq/rabbitmq_base.cpp

@@ -0,0 +1,981 @@
+
+#include "rabbitmq_base.h"
+
+Rabbitmq_base::Rabbitmq_base() {
+    m_rabbitmq_status = RABBITMQ_STATUS_UNKNOW;
+
+    mp_connect = NULL;
+    mp_socket = NULL;
+    m_port = 0;
+
+    mp_receive_analysis_thread = NULL;
+    mp_send_thread = NULL;
+    mp_encapsulate_status_thread = NULL;
+    m_encapsulate_status_cycle_time = 1000;//默认1000ms,就自动封装一次状态信息
+
+    check_msg_callback = NULL;
+    check_executer_callback = NULL;
+    execute_msg_callback = NULL;
+    encapsulate_status_callback = NULL;
+
+}
+
+Rabbitmq_base::~Rabbitmq_base() {
+    rabbitmq_uninit();
+}
+
+//初始化 通信 模块。如下三选一
+Error_manager Rabbitmq_base::rabbitmq_init() {
+    return rabbitmq_init_from_protobuf(RABBITMQ_PARAMETER_PATH);
+}
+
+//初始化 通信 模块。从文件读取
+Error_manager Rabbitmq_base::rabbitmq_init_from_protobuf(std::string prototxt_path) {
+    Rabbitmq_proto::Rabbitmq_parameter_all t_rabbitmq_parameter_all;
+    if (loadProtobufFile(prototxt_path, t_rabbitmq_parameter_all) != SUCCESS) {
+        return Error_manager(RABBITMQ_READ_PROTOBUF_ERROR, MINOR_ERROR,
+                             "rabbitmq_init_from_protobuf read_proto_param  failed");
+    }
+    return rabbitmq_init_from_protobuf(t_rabbitmq_parameter_all);
+}
+
+//初始化 通信 模块。从protobuf读取
+Error_manager
+Rabbitmq_base::rabbitmq_init_from_protobuf(Rabbitmq_proto::Rabbitmq_parameter_all &rabbitmq_parameter_all) {
+    LOG(INFO) << " ---Rabbitmq_base::rabbitmq_init_from_protobuf() run--- " << this;
+
+    int t_status = 0;        //状态
+    amqp_rpc_reply_t t_reply;    //reply答复结果
+    Error_manager t_error;
+    m_rabbitmq_parameter_all = rabbitmq_parameter_all;
+
+    for (auto &queue:rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_reciever_vector()) {
+        mp_rabbitmq_reciever.insert(std::pair<const std::string, Rabbitmq_proto::Rabbitmq_channel_queue_consume>(queue.routing_key(), queue));
+    }
+    for (auto &queue:rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_request_vector()) {
+        mp_rabbitmq_reciever.insert(std::pair<const std::string, Rabbitmq_proto::Rabbitmq_channel_queue_consume>(queue.routing_key(), queue));
+    }
+    for (auto &queue:rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_status_vector()) {
+        mp_rabbitmq_reciever.insert(std::pair<const std::string, Rabbitmq_proto::Rabbitmq_channel_queue_consume>(queue.routing_key(), queue));
+    }
+
+    //amqp_new_connection 新建amqp的连接配置,里面只有连接状态参数
+    // 返回amqp_connection_state_t_ *, 函数内部分配内存, amqp_destroy_connection()可以释放内存, 内存不为空则成功
+    mp_connect = amqp_new_connection();
+    if (mp_connect == nullptr) {
+        return Error_manager(Error_code::RABBITMQ_AMQP_NEW_CONNECTION_ERROR, Error_level::MINOR_ERROR,
+                             "amqp_new_connection fun error ");
+    }
+
+    //amqp_tcp_socket_new 新建tcp_socket连接
+    // 返回amqp_socket_t *, 函数内部分配内存, amqp_connection_close()可以释放内存, 内存不为空则成功
+    mp_socket = amqp_tcp_socket_new(mp_connect);
+    if (mp_socket == nullptr) {
+        return Error_manager(Error_code::RABBITMQ_AMQP_TCP_SOCKET_NEW_ERROR, Error_level::MINOR_ERROR,
+                             "amqp_tcp_socket_new fun error ");
+    }
+
+    //载入外部参数
+    if (rabbitmq_parameter_all.rabbitmq_parameters().has_ip() &&
+        rabbitmq_parameter_all.rabbitmq_parameters().has_port() &&
+        rabbitmq_parameter_all.rabbitmq_parameters().has_user() &&
+        rabbitmq_parameter_all.rabbitmq_parameters().has_password()) {
+        m_ip = rabbitmq_parameter_all.rabbitmq_parameters().ip();
+        m_port = rabbitmq_parameter_all.rabbitmq_parameters().port();
+        m_user = rabbitmq_parameter_all.rabbitmq_parameters().user();
+        m_password = rabbitmq_parameter_all.rabbitmq_parameters().password();
+    } else {
+        return Error_manager(Error_code::RABBITMQ_PROTOBUF_LOSS_ERROR, Error_level::MINOR_ERROR,
+                             " rabbitmq_parameter_all.rabbitmq_parameters() The data is not complete   ");
+    }
+
+    //amqp_socket_open 打开socket连接, 输入ip和port,
+    // 成功返回AMQP_STATUS_OK = 0x0, 失败返回错误状态码, 详见 enum amqp_status_enum_
+    //只需要设置配置服务器的ip和port, 不需要配置子节点客户端的ip和port, 在后面配置channel通道时,进行设置.
+    t_status = amqp_socket_open(mp_socket, m_ip.c_str(), m_port);
+    if (t_status != AMQP_STATUS_OK) {
+        return Error_manager(Error_code::RABBITMQ_AMQP_SOCKET_OPEN_ERROR, Error_level::MINOR_ERROR,
+                             amqp_error_to_string(t_status, "amqp_socket_open"));
+    }
+
+    //amqp_login() 登录代理服务器,
+    //输入 连接参数结构体 amqp_connection_state_t,
+    //输入 连接地址, 前面 amqp_socket_open() 已经输入了,这里默认写"/"
+    //输入 连接通道最大值, 默认值0表示没有限制
+    //输入 连接帧率最大值, 默认值是131072 (128KB)
+    //输入 心跳帧之间的秒数, 默认值0禁用心跳
+    //输入 身份验证模式, 	AMQP_SASL_METHOD_PLAIN, 追加用户名和密码
+    //					AMQP_SASL_METHOD_EXTERNAL, 追加身份证
+    //返回 结果的结构体 amqp_rpc_reply_t
+    //	amqp_response_type_enum reply_type 登录成功是 AMQP_RESPONSE_NORMAL
+    //		失败:如果是 reply_type == AMQP_RESPONSE_SERVER_EXCEPTION, 服务器连接错误, 错误信息在 amqp_method_t reply
+    //		失败:如果是 reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION, 库函数错误, 错误信息在 int library_error
+    t_reply = amqp_login(mp_connect, "/", 0, 131072, 0,
+                         AMQP_SASL_METHOD_PLAIN, m_user.c_str(), m_password.c_str());
+    if (t_reply.reply_type != AMQP_RESPONSE_NORMAL) {
+        return Error_manager(Error_code::RABBITMQ_AMQP_LOGIN_ERROR, Error_level::MINOR_ERROR,
+                             amqp_error_to_string(t_reply, "amqp_login"));
+    }
+
+    //清除channel_map, 通道的缓存,防止重复开启, (channel允许重复使用, 但是不能重复初始化)
+    m_channel_map.clear();
+
+    //创建通道队列消费者, (交换机和永久队列不在代码里创建,请在服务器上手动创建)
+    t_error = rabbitmq_new_channel_queue_consume(rabbitmq_parameter_all);
+    if (t_error != Error_code::SUCCESS) {
+        return t_error;
+    }
+
+    //启动通信, 开启线程, run thread
+    t_error = rabbitmq_run();
+    if (t_error != Error_code::SUCCESS) {
+        return t_error;
+    }
+    return Error_code::SUCCESS;
+}
+
+//创建通道队列消费者, (交换机和永久队列不在代码里创建,请在服务器上手动创建)
+Error_manager
+Rabbitmq_base::rabbitmq_new_channel_queue_consume(Rabbitmq_proto::Rabbitmq_parameter_all &rabbitmq_parameter_all) {
+    int t_status = 0;        //状态
+    amqp_rpc_reply_t t_reply;    //reply答复结果
+    Error_manager t_error;
+
+    ///Rabbitmq 接受的通道,队列和消费者, 多个
+    for (int i = 0; i < rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_reciever_vector_size(); ++i) {
+        //Rabbitmq 配置的通道,队列和消费者,
+        Rabbitmq_proto::Rabbitmq_channel_queue_consume t_inf =
+                rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_reciever_vector(i);
+
+        //通道查重,防止重复开启(channel允许重复使用, 但是不能重复初始化)
+        if (m_channel_map.find(t_inf.channel()) == m_channel_map.end()) {
+            //amqp_channel_open() 打开连接通道, 同一台电脑可以多个进程和线程进行连接服务器, 每个连接需要自己独特的通道.
+            amqp_channel_open(mp_connect, t_inf.channel());
+            //amqp_get_rpc_reply() 获取当前网络连接的状态结果.
+            t_reply = amqp_get_rpc_reply(mp_connect);
+            if (t_reply.reply_type != AMQP_RESPONSE_NORMAL) {
+                return Error_manager(Error_code::RABBITMQ_AMQP_CHANNEL_OPEN_ERROR, Error_level::MINOR_ERROR,
+                                     amqp_error_to_string(t_reply, "amqp_channel_open"));
+            }
+            if (t_inf.consume_no_ack() == 0) {
+                //amqp_basic_qos设置通道每次只能接受一条消息, 直到该消息被ack,才能接受下一条.状态消息可以继续接受
+                //uint16_t prefetch_count 同时接受消息的个数, 这里固定写1,
+                //配合 amqp_basic_qos 和 amqp_basic_ack , 来阻塞这个通道的接受消息
+                //注:请求消息no_ack==0, 当接受一条指令后,该通道被阻塞,其他通道仍然正常接受, 等到任务被执行完,手动调用amqp_basic_ack函数, 则可以继续接受请求消息.
+                //注:状态消息no_ack==1, 当接受一条指令后,该状态消息立刻被删除,然后可以继续接受下一条状态消息.
+                amqp_basic_qos(mp_connect, t_inf.channel(), 0, PREFETCH_COUNT, 0);
+            }
+            m_channel_map[t_inf.channel()] = true;
+        }
+
+        //临时队列需要代码创建, 永久队列需要在服务器上提前手动创建
+        if (t_inf.queue_durable() == 0) {
+            //目前只填充超时时间,  x-message-ttl 队列接受消息 的超时时间 (单位毫秒)
+            if (t_inf.queue_meassage_ttl() != 0) {
+                amqp_table_t t_arguments;        //队列的扩展属性 num_entries 是map长度, amqp_table_entry_t_ 是map指针
+                //目前只填充超时时间,  x-message-ttl 队列接受消息 的超时时间 (单位毫秒)
+                t_arguments.num_entries = 1;
+                amqp_table_entry_t_ t_map_arg;
+                t_map_arg.key = amqp_cstring_bytes("x-message-ttl");        //需要配置的参数
+                t_map_arg.value.kind = AMQP_FIELD_KIND_U16;                                //需要配置的数据类型, 如果是字符串, 写 AMQP_FIELD_KIND_UTF8
+                t_map_arg.value.value.u16 = t_inf.queue_meassage_ttl();                    //需要配置的数值
+                t_arguments.entries = &t_map_arg;
+
+                //amqp_queue_declare() 队列声明, 就是创建新的队列.
+                //输入 amqp_connection_state_t state 连接状态参数的结构体
+                //输入 amqp_channel_t channel 连接通道的编号
+                //输入 amqp_bytes_t queue 队列名称,可以手动命名,如果写空,系统就会自动分配, 手动写amqp_cstring_bytes("abcdefg"), 默认空 amqp_empty_bytes
+                //输入 amqp_boolean_t passive 是否被动,默认0
+                //输入 amqp_boolean_t durable 是否持久,默认0, 节点代码可以创建临时队列(所有权归节点), 服务器手动创建永久队列(所有权归服务器)
+                //		1表示永久队列,当节点死掉,队列在服务器保留,仍然可以接受数据,节点上线后,可以接受掉线期间的所有数据
+                //		0表示临时队列,当节点死掉,队列消失,不再接受数据,直到下次恢复正常
+                //输入 amqp_boolean_t exclusive 是否独立,默认0
+                //输入 amqp_boolean_t auto_delete 是否自动删除,默认0, 1表示消息被消费者接受后,就自动删除消息, 当接收端断连后,队列也会才删除,
+                // 													一般情况下设为0,然后让接受者手动删除.
+                //输入 amqp_table_t arguments 预留参数,默认空 amqp_empty_table
+                //返回 amqp_queue_declare_ok_t *	返回结果
+                amqp_queue_declare(mp_connect, t_inf.channel(), amqp_cstring_bytes(t_inf.queue_name().c_str()),
+                                   t_inf.queue_passive(), t_inf.queue_durable(), t_inf.queue_exclusive(),
+                                   t_inf.queue_auto_delete(), t_arguments);
+            } else {
+                //amqp_queue_declare() 队列声明, 就是创建新的队列.
+                //输入 amqp_connection_state_t state 连接状态参数的结构体
+                //输入 amqp_channel_t channel 连接通道的编号
+                //输入 amqp_bytes_t queue 队列名称,可以手动命名,如果写空,系统就会自动分配, 手动写amqp_cstring_bytes("abcdefg"), 默认空 amqp_empty_bytes
+                //输入 amqp_boolean_t passive 是否被动,默认0
+                //输入 amqp_boolean_t durable 是否持久,默认0, 节点代码可以创建临时队列(所有权归节点), 服务器手动创建永久队列(所有权归服务器)
+                //		1表示永久队列,当节点死掉,队列在服务器保留,仍然可以接受数据,节点上线后,可以接受掉线期间的所有数据
+                //		0表示临时队列,当节点死掉,队列消失,不再接受数据,直到下次恢复正常
+                //输入 amqp_boolean_t exclusive 是否独立,默认0
+                //输入 amqp_boolean_t auto_delete 是否自动删除,默认0, 1表示消息被消费者接受后,就自动删除消息, 当接收端断连后,队列也会才删除,
+                // 													一般情况下设为0,然后让接受者手动删除.
+                //输入 amqp_table_t arguments 预留参数,默认空 amqp_empty_table
+                //返回 amqp_queue_declare_ok_t *	返回结果
+                amqp_queue_declare(mp_connect, t_inf.channel(), amqp_cstring_bytes(t_inf.queue_name().c_str()),
+                                   t_inf.queue_passive(), t_inf.queue_durable(), t_inf.queue_exclusive(),
+                                   t_inf.queue_auto_delete(), amqp_empty_table);
+            }
+
+
+            //amqp_queue_bind 队列绑定, 将队列加载到服务器的交换机下面, 交换机收到消息后,就会检查key,然后放到指定的队列.
+            //输入 amqp_connection_state_t state 连接状态参数的结构体
+            //输入 amqp_channel_t channel 连接通道的编号
+            //输入 amqp_bytes_t queue 队列名称,
+            //输入 amqp_bytes_t exchange 交换机模式字符串
+            //输入 amqp_bytes_t bindingkey 绑定密钥字符串, 交换机的判断规则. 发送端的 routingkey 和 接收端的 bindingkey 需要保持一致
+            //输入 amqp_table_t arguments 预留参数,默认空 amqp_empty_table
+            //返回 amqp_queue_bind_ok_t *	返回结果
+            //注注注注注意了, 队列绑定交换机时,必须保证交换机是有效的.否则报错
+            amqp_queue_bind(mp_connect, t_inf.channel(), amqp_cstring_bytes(t_inf.queue_name().c_str()),
+                            amqp_cstring_bytes(t_inf.exchange_name().c_str()),
+                            amqp_cstring_bytes(t_inf.binding_key().c_str()), amqp_empty_table);
+
+            amqp_rpc_reply_t t_reply = amqp_get_rpc_reply(mp_connect);
+            if (t_reply.reply_type != AMQP_RESPONSE_NORMAL) {
+                return Error_manager(Error_code::RABBITMQ_AMQP_QUEUE_BIND_ERROR, Error_level::MINOR_ERROR,
+                                     amqp_error_to_string(t_reply, "amqp_queue_bind"));
+            }
+        }
+
+        //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 是否非本地, 默认0,表示本地
+        //输入 amqp_boolean_t no_ack, 是否确认应答,默认0,表示接收后需要应答
+        //输入 amqp_boolean_t exclusive 是否独立,默认0
+        //输入 amqp_table_t arguments 预留参数,默认空 amqp_empty_table
+        //返回 amqp_basic_consume_ok_t *	返回结果
+        //注注注注注意了, 接受端绑定队列时,必须保证队列是有效的,否则报错,
+        amqp_basic_consume(mp_connect, t_inf.channel(), amqp_cstring_bytes(t_inf.queue_name().c_str()),
+                           amqp_cstring_bytes(t_inf.consume_name().c_str()), t_inf.consume_no_local(),
+                           t_inf.consume_no_ack(), t_inf.consume_exclusive(), amqp_empty_table);
+        amqp_rpc_reply_t t_reply = amqp_get_rpc_reply(mp_connect);
+        if (t_reply.reply_type != AMQP_RESPONSE_NORMAL) {
+            return Error_manager(Error_code::RABBITMQ_AMQP_NEW_CONSUME_ERROR, Error_level::MINOR_ERROR,
+                                 amqp_error_to_string(t_reply, "amqp_basic_consume"));
+        }
+    }
+
+    //Rabbitmq 发送请求的通道
+    for (int i = 0; i < rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_request_vector_size(); ++i) {
+        //Rabbitmq 配置发送通道
+        Rabbitmq_proto::Rabbitmq_channel_queue_consume t_inf1 =
+                rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_request_vector(i);
+
+        //通道查重,防止重复开启(channel允许重复使用, 但是不能重复初始化)
+        if (m_channel_map.find(t_inf1.channel()) == m_channel_map.end()) {
+            //amqp_channel_open() 打开连接通道, 同一台电脑可以多个进程和线程进行连接服务器, 每个连接需要自己独特的通道.
+            amqp_channel_open(mp_connect, t_inf1.channel());
+            //amqp_get_rpc_reply() 获取当前网络连接的状态结果.
+            t_reply = amqp_get_rpc_reply(mp_connect);
+            if (t_reply.reply_type != AMQP_RESPONSE_NORMAL) {
+                return Error_manager(Error_code::RABBITMQ_AMQP_CHANNEL_OPEN_ERROR, Error_level::MINOR_ERROR,
+                                     amqp_error_to_string(t_reply, "amqp_channel_open"));
+            }
+            m_channel_map[t_inf1.channel()] = true;
+        }
+    }
+
+    //Rabbitmq 发送状态的通道
+    for (int i = 0; i < rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_status_vector_size(); ++i) {
+        //Rabbitmq 配置发送通道
+        Rabbitmq_proto::Rabbitmq_channel_queue_consume t_inf2 =
+                rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_status_vector(i);
+
+        //通道查重,防止重复开启(channel允许重复使用, 但是不能重复初始化)
+        if (m_channel_map.find(t_inf2.channel()) == m_channel_map.end()) {
+            //amqp_channel_open() 打开连接通道, 同一台电脑可以多个进程和线程进行连接服务器, 每个连接需要自己独特的通道.
+            amqp_channel_open(mp_connect, t_inf2.channel());
+            //amqp_get_rpc_reply() 获取当前网络连接的状态结果.
+            t_reply = amqp_get_rpc_reply(mp_connect);
+            if (t_reply.reply_type != AMQP_RESPONSE_NORMAL) {
+                return Error_manager(Error_code::RABBITMQ_AMQP_CHANNEL_OPEN_ERROR, Error_level::MINOR_ERROR,
+                                     amqp_error_to_string(t_reply, "amqp_channel_open"));
+            }
+            m_channel_map[t_inf2.channel()] = true;
+        }
+    }
+
+    return Error_code::SUCCESS;
+}
+
+//启动通信, 开启线程, run thread
+Error_manager Rabbitmq_base::rabbitmq_run() {
+    //启动 线程。
+    //接受线程默认循环, 内部的 amqp_consume_message 进行等待, 超时1ms
+    m_receive_analysis_condition.reset(false, true, false);
+    mp_receive_analysis_thread = new std::thread(&Rabbitmq_base::receive_analysis_thread, this);
+    //发送线程默认循环, 内部的wait_and_pop进行等待,
+    m_send_condition.reset(false, true, false);
+    mp_send_thread = new std::thread(&Rabbitmq_base::send_thread, this);
+    //封装线程默认等待, ...., 超时1秒, 超时后主动 封装心跳和状态信息,
+    m_encapsulate_status_condition.reset(false, false, false);
+    mp_encapsulate_status_thread = new std::thread(&Rabbitmq_base::encapsulate_status_thread, this);
+
+    m_rabbitmq_status = RABBITMQ_STATUS_READY;
+    return Error_code::SUCCESS;
+}
+
+//反初始化 通信 模块。
+Error_manager Rabbitmq_base::rabbitmq_uninit() {
+    LOG(INFO) << " ---Rabbitmq_base::rabbitmq_uninit() run--- " << this;
+
+    //终止list,防止 wait_and_pop 阻塞线程。
+    m_send_list.termination_list();
+
+    //杀死线程,强制退出
+    if (mp_receive_analysis_thread) {
+        m_receive_analysis_condition.kill_all();
+    }
+    if (mp_send_thread) {
+        m_send_condition.kill_all();
+    }
+    if (mp_encapsulate_status_thread) {
+        m_encapsulate_status_condition.kill_all();
+    }
+
+
+    //回收线程的资源
+    if (mp_receive_analysis_thread) {
+        mp_receive_analysis_thread->join();
+        delete mp_receive_analysis_thread;
+        mp_receive_analysis_thread = NULL;
+    }
+    if (mp_send_thread) {
+        mp_send_thread->join();
+        delete mp_send_thread;
+        mp_send_thread = NULL;
+    }
+    if (mp_encapsulate_status_thread) {
+        mp_encapsulate_status_thread->join();
+        delete mp_encapsulate_status_thread;
+        mp_encapsulate_status_thread = NULL;
+    }
+
+    //清空list
+    m_send_list.clear_and_delete();
+
+    if (m_rabbitmq_status == RABBITMQ_STATUS_READY) {
+        for (auto iter = m_channel_map.begin(); iter != m_channel_map.end(); ++iter) {
+            amqp_channel_close(mp_connect, iter->first, AMQP_REPLY_SUCCESS);
+        }
+        amqp_connection_close(mp_connect, AMQP_REPLY_SUCCESS);
+        amqp_destroy_connection(mp_connect);
+    }
+
+    m_rabbitmq_status = RABBITMQ_STATUS_UNKNOW;
+    return Error_code::SUCCESS;
+}
+
+//重连, 快速uninit, init
+Error_manager Rabbitmq_base::rabbitmq_reconnnect() {
+    //重连全程加锁,防止其他线程运行.
+    std::unique_lock<std::mutex> lk(m_mutex);
+    m_rabbitmq_status = RABBITMQ_STATUS_RECONNNECT;
+
+    //断开连接
+    for (auto iter = m_channel_map.begin(); iter != m_channel_map.end(); ++iter) {
+        amqp_channel_close(mp_connect, iter->first, AMQP_REPLY_SUCCESS);
+    }
+    amqp_connection_close(mp_connect, AMQP_REPLY_SUCCESS);
+    amqp_destroy_connection(mp_connect);
+
+    //重新连接,线程不需要重启
+    LOG(INFO) << " ---Rabbitmq_base::rabbitmq_reconnnect() run--- " << this;
+
+    int t_status = 0;        //状态
+    amqp_rpc_reply_t t_reply;    //reply答复结果
+    Error_manager t_error;
+
+    //amqp_new_connection 新建amqp的连接配置,里面只有连接状态参数
+    // 返回amqp_connection_state_t_ *, 函数内部分配内存, amqp_destroy_connection()可以释放内存, 内存不为空则成功
+    mp_connect = amqp_new_connection();
+    if (mp_connect == NULL) {
+        return Error_manager(Error_code::RABBITMQ_AMQP_NEW_CONNECTION_ERROR, Error_level::MINOR_ERROR,
+                             "amqp_new_connection fun error ");
+    }
+
+    //amqp_tcp_socket_new 新建tcp_socket连接
+    // 返回amqp_socket_t *, 函数内部分配内存, amqp_connection_close()可以释放内存, 内存不为空则成功
+    mp_socket = amqp_tcp_socket_new(mp_connect);
+    if (mp_socket == NULL) {
+        return Error_manager(Error_code::RABBITMQ_AMQP_TCP_SOCKET_NEW_ERROR, Error_level::MINOR_ERROR,
+                             "amqp_tcp_socket_new fun error ");
+    }
+
+    //载入外部参数
+    if (m_rabbitmq_parameter_all.rabbitmq_parameters().has_ip() &&
+        m_rabbitmq_parameter_all.rabbitmq_parameters().has_port() &&
+        m_rabbitmq_parameter_all.rabbitmq_parameters().has_user() &&
+        m_rabbitmq_parameter_all.rabbitmq_parameters().has_password()) {
+        m_ip = m_rabbitmq_parameter_all.rabbitmq_parameters().ip();
+        m_port = m_rabbitmq_parameter_all.rabbitmq_parameters().port();
+        m_user = m_rabbitmq_parameter_all.rabbitmq_parameters().user();
+        m_password = m_rabbitmq_parameter_all.rabbitmq_parameters().password();
+    } else {
+        return Error_manager(Error_code::RABBITMQ_PROTOBUF_LOSS_ERROR, Error_level::MINOR_ERROR,
+                             " rabbitmq_parameter_all.rabbitmq_parameters() The data is not complete   ");
+    }
+
+    //amqp_socket_open 打开socket连接, 输入ip和port,
+    // 成功返回AMQP_STATUS_OK = 0x0, 失败返回错误状态码, 详见 enum amqp_status_enum_
+    //只需要设置配置服务器的ip和port, 不需要配置子节点客户端的ip和port, 在后面配置channel通道时,进行设置.
+    t_status = amqp_socket_open(mp_socket, m_ip.c_str(), m_port);
+    if (t_status != AMQP_STATUS_OK) {
+        return Error_manager(Error_code::RABBITMQ_AMQP_SOCKET_OPEN_ERROR, Error_level::MINOR_ERROR,
+                             amqp_error_to_string(t_status, "amqp_socket_open"));
+    }
+
+    //amqp_login() 登录代理服务器,
+    //输入 连接参数结构体 amqp_connection_state_t,
+    //输入 连接地址, 前面 amqp_socket_open() 已经输入了,这里默认写"/"
+    //输入 连接通道最大值, 默认值0表示没有限制
+    //输入 连接帧率最大值, 默认值是131072 (128KB)
+    //输入 心跳帧之间的秒数, 默认值0禁用心跳
+    //输入 身份验证模式, 	AMQP_SASL_METHOD_PLAIN, 追加用户名和密码
+    //					AMQP_SASL_METHOD_EXTERNAL, 追加身份证
+    //返回 结果的结构体 amqp_rpc_reply_t
+    //	amqp_response_type_enum reply_type 登录成功是 AMQP_RESPONSE_NORMAL
+    //		失败:如果是 reply_type == AMQP_RESPONSE_SERVER_EXCEPTION, 服务器连接错误, 错误信息在 amqp_method_t reply
+    //		失败:如果是 reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION, 库函数错误, 错误信息在 int library_error
+    t_reply = amqp_login(mp_connect, "/", 0, 131072, 0,
+                         AMQP_SASL_METHOD_PLAIN, m_user.c_str(), m_password.c_str());
+    if (t_reply.reply_type != AMQP_RESPONSE_NORMAL) {
+        return Error_manager(Error_code::RABBITMQ_AMQP_LOGIN_ERROR, Error_level::MINOR_ERROR,
+                             amqp_error_to_string(t_reply, "amqp_login"));
+    }
+
+    //清除channel_map, 通道的缓存,防止重复开启, (channel允许重复使用, 但是不能重复初始化)
+    m_channel_map.clear();
+
+    //创建通道队列消费者, (交换机和永久队列不在代码里创建,请在服务器上手动创建)
+    t_error = rabbitmq_new_channel_queue_consume(m_rabbitmq_parameter_all);
+    if (t_error != Error_code::SUCCESS) {
+        return t_error;
+    }
+
+    //不用重启线程
+    return Error_code::SUCCESS;
+
+}
+
+//设置 自动封装状态的时间周期
+void Rabbitmq_base::set_encapsulate_status_cycle_time(unsigned int encapsulate_status_cycle_time) {
+    m_encapsulate_status_cycle_time = encapsulate_status_cycle_time;
+}
+
+//设置回调函数check_msg_callback
+void Rabbitmq_base::set_check_msg_callback(Error_manager (*callback)(Rabbitmq_message *p_msg)) {
+    check_msg_callback = callback;
+}
+
+//设置回调函数check_executer_callback
+void Rabbitmq_base::set_check_executer_callback(Error_manager (*callback)(Rabbitmq_message *p_msg)) {
+    check_executer_callback = callback;
+}
+
+//设置回调函数execute_msg_callback
+void Rabbitmq_base::set_execute_msg_callback(Error_manager (*callback)(Rabbitmq_message *p_msg)) {
+    execute_msg_callback = callback;
+}
+
+//设置回调函数encapsulate_status_callback
+void Rabbitmq_base::set_encapsulate_status_callback(Error_manager (*callback)()) {
+    encapsulate_status_callback = callback;
+}
+
+//mp_receive_analysis_thread 接受解析 执行函数,
+void Rabbitmq_base::receive_analysis_thread() {
+    LOG(INFO) << " Rabbitmq_base::receive_analysis_thread start " << this;
+
+    //通信接受线程, 负责接受socket消息, 并存入 m_receive_data_list
+    while (m_receive_analysis_condition.is_alive()) {
+        //这里就不需要超时等待了, rabbitmq的接受函数可以配置等待超时....
+//		m_receive_analysis_condition.wait_for_ex(std::chrono::microseconds(1));
+        m_receive_analysis_condition.wait();
+        if (m_receive_analysis_condition.is_alive()) {
+            std::this_thread::sleep_for(std::chrono::microseconds(100));
+            std::this_thread::yield();
+
+            amqp_rpc_reply_t t_reply;        //运行结果
+            amqp_envelope_t t_envelope;        //数据包, 含有一些包裹属性和数据内容
+            //接受消息等待超时,默认1000us, 当收到消息后,立刻通过阻塞,否则等待超时后通过阻塞
+            struct timeval t_timeout;        //超时时间, 默认1ms
+            t_timeout.tv_sec = 0;
+            t_timeout.tv_usec = 1000;
+
+            {//这个大括号表示只对 recv 和 send 加锁, 不要因为后面的复杂逻辑影响通信效率
+                std::unique_lock<std::mutex> lk(m_mutex);
+                //允许释放连接参数状态的内存,
+                // 因为这个连接是底层分配的内存,是全局的. 为了开启多个连接,就要重复使用
+                //这里释放之后,其他代码就开启多线程开启新的连接了.
+                amqp_maybe_release_buffers(mp_connect);
+                //amqp_consume_message 接受消息, 阻塞函数,可以设置超时.
+                //输入 amqp_connection_state_t state 连接状态参数的结构体
+                //输入 amqp_envelope_t *envelope 接受数据包的指针, 成功接收到数据后,数据包会覆盖
+                //输入 const struct timeval *timeout 超时时间, 防止阻塞. 传入NULL就是完全阻塞.
+                //输入 int flags 未使用, 默认0
+                //输入 amqp_connection_state_t state 连接状态参数的结构体
+                //返回 状态结果的结构体 amqp_rpc_reply_t
+                //	amqp_response_type_enum reply_type 成功是 AMQP_RESPONSE_NORMAL
+                //		失败:如果是 reply_type == AMQP_RESPONSE_SERVER_EXCEPTION, 服务器连接错误, 错误信息在 amqp_method_t reply
+                //		失败:如果是 reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION, 库函数错误, 错误信息在 int library_error
+                t_reply = amqp_consume_message(mp_connect, &t_envelope, &t_timeout, 0);
+            }
+
+            if (AMQP_RESPONSE_NORMAL == t_reply.reply_type)//正常接受到消息
+            {
+
+
+                m_rabbitmq_status = RABBITMQ_STATUS_READY;
+                //从t_envelope数据包里面提取信息
+                std::string t_receive_string = std::string((char *) t_envelope.message.body.bytes,
+                                                           t_envelope.message.body.len);
+                int t_channel = t_envelope.channel;
+                int t_delivery_tag = t_envelope.delivery_tag;
+                std::string t_exchange_name = std::string((char *) t_envelope.exchange.bytes, t_envelope.exchange.len);
+                std::string t_routing_key = std::string((char *) t_envelope.routing_key.bytes,
+                                                        t_envelope.routing_key.len);
+                //如果这里接受到了消息, 在这提前解析消息最前面的Base_msg (消息公共内容), 用于后续的check
+                message::Base_msg t_base_msg;
+//				if( t_base_msg.ParseFromString(t_receive_string) )
+
+                //删除 message::Base_msg 里面的 message::Base_info的机制,完全依赖服务器来分发消息
+                if (true) {
+                    //第一次解析之后转化为, Communication_message, 自定义的通信消息格式
+                    Rabbitmq_message t_rabbitmq_message;
+                    t_rabbitmq_message.reset(t_base_msg.base_info(), t_receive_string, t_channel, t_delivery_tag,
+                                             t_exchange_name, t_routing_key);
+                    //检查消息是否有效, 主要检查消息类型和接受者, 判断这条消息是不是给我的.
+                    if (check_msg(&t_rabbitmq_message) == SUCCESS) {
+                        //这里直接就用当前线程进行处理,
+                        //检查消息是否可以被处理
+                        if (check_executer(&t_rabbitmq_message) == SUCCESS) {
+                            //处理消息
+                            if (execute_msg(&t_rabbitmq_message) == SUCCESS) {
+
+                            }
+                            //else不做处理
+                        }
+                        //else不做处理
+                    }
+                    //else不做处理
+                }
+                    //else解析失败, 就当做什么也没发生, 认为接收消息无效,
+                else {
+                    std::cout << " huli test :::: " << " t_receive_string = " << t_receive_string << std::endl;
+                    if (t_channel == 401) {
+                        amqp_basic_ack(mp_connect, t_channel, t_delivery_tag, 0);
+                    }
+                }
+
+                //amqp_destroy_envelope 销毁数据包, 只有接受成功, t_envelope才有内存
+                amqp_destroy_envelope(&t_envelope);
+            } else//没有接受到消息
+            {
+                //超时报错,不做处理, continue
+                //注注注注注意了, 没有收到消息会超时报错, res.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION, res.library_error = -13, (-0x000D request timed out)
+                if (t_reply.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION && t_reply.library_error == -13) {
+                    m_rabbitmq_status = RABBITMQ_STATUS_READY;
+                    continue;
+                } else//其他报错,特殊处理
+                {
+                    //need
+
+                    std::string error_description = amqp_error_to_string(t_reply, "amqp_consume_message");
+                    LOG(WARNING) << " huli test 123123123:::: " << " error_description = " << error_description
+                              << std::endl;
+//					return Error_manager(Error_code::RABBITMQ_AMQP_CONSUME_MESSAGE_ERROR, Error_level::MINOR_ERROR,
+//											 amqp_error_to_string(t_reply, "amqp_consume_message") );
+                    //重启
+                    rabbitmq_reconnnect();
+
+                }
+            }
+        }
+    }
+
+    LOG(INFO) << " Rabbitmq_base::receive_analysis_thread end " << this;
+    return;
+}
+
+//检查消息是否有效, 主要检查消息类型和接受者, 判断这条消息是不是给我的., 需要子类重载
+Error_manager Rabbitmq_base::check_msg(Rabbitmq_message *p_msg) {
+    if (check_msg_callback != NULL) {
+        return check_msg_callback(p_msg);
+    }
+    return Error_code::SUCCESS;
+}
+
+//检查执行者的状态, 判断能否处理这条消息, 需要子类重载
+Error_manager Rabbitmq_base::check_executer(Rabbitmq_message *p_msg) {
+    if (check_executer_callback != NULL) {
+        return check_executer_callback(p_msg);
+    }
+    return Error_code::SUCCESS;
+}
+
+//处理消息, 需要子类重载
+Error_manager Rabbitmq_base::execute_msg(Rabbitmq_message *p_msg) {
+    if (execute_msg_callback != NULL) {
+        return execute_msg_callback(p_msg);
+    } else {
+        //需要子类重载
+        std::cout << " huli test :::: " << " execute_msg Rabbitmq_message = " << p_msg->get_message_buf() << std::endl;
+
+        //如果是请求消息,那么在子节点继承的时候一定要记得调用
+        //配置rabbitmq.proto时,  如果consume_no_ack == 0 , 一定要手动调用 amqp_basic_ack
+        int consume_no_ack = 1;
+        if (consume_no_ack == 0 || p_msg->m_channel == 401) {
+            //amqp_basic_ack 确认消息, 通知服务器队列手动删除消息.
+            //输入 amqp_connection_state_t state 连接状态参数的结构体
+            //输入 amqp_channel_t channel 连接通道的编号
+            //输入 uint64_t delivery_tag  消息传递编号,
+            //输入 amqp_boolean_t multiple 多个标记位, 默认0,   1表示删除1~delivery_tag的所有消息, 不删除大于delivery_tag的, 0表示只删除这一条
+            int ack_result = amqp_basic_ack(mp_connect, p_msg->m_channel, p_msg->m_delivery_tag, 0);
+        }
+    }
+    return Error_code::SUCCESS;
+}
+
+//ack_msg 处理完消息后, 手动确认消息, 通知服务器队列删除消息.
+//执行者在execute_msg里面可以调用这个函数, 或者回调也行.
+Error_manager Rabbitmq_base::ack_msg(Rabbitmq_message *p_msg) {
+    //amqp_basic_ack 确认消息, 通知服务器队列手动删除消息.
+    //输入 amqp_connection_state_t state 连接状态参数的结构体
+    //输入 amqp_channel_t channel 连接通道的编号
+    //输入 uint64_t delivery_tag  消息传递编号,
+    //输入 amqp_boolean_t multiple 多个标记位, 默认0,   1表示删除1~delivery_tag的所有消息, 不删除大于delivery_tag的, 0表示只删除这一条
+    int ack_result = amqp_basic_ack(mp_connect, p_msg->m_channel, p_msg->m_delivery_tag, 0);
+    if (ack_result != 0) {
+        return Error_manager(Error_code::RABBITMQ_AMQP_BASIC_ACK_ERROR, Error_level::MINOR_ERROR,
+                             amqp_error_to_string(ack_result, "amqp_basic_ack"));
+    }
+    return Error_code::SUCCESS;
+}
+
+//mp_send_thread 发送线程执行函数,
+void Rabbitmq_base::send_thread() {
+    LOG(INFO) << " Rabbitmq_base::send_thread start " << this;
+
+    //通信发送线程, 负责巡检m_send_list, 并发送消息
+    while (m_send_condition.is_alive()) {
+        m_send_condition.wait();
+        if (m_send_condition.is_alive()) {
+            std::this_thread::yield();
+
+            Rabbitmq_message *tp_msg = NULL;
+            int t_result = 0;
+            //这里 wait_and_pop 会使用链表内部的 m_data_cond 条件变量来控制等待,
+            //封装线程使用push的时候, 会唤醒线程并通过等待, 此时 m_send_data_condition 是一直通过的.
+            //如果需要退出, 那么就要 m_send_data_list.termination_list();	和 m_send_data_condition.kill_all();
+            bool is_pop = m_send_list.wait_and_pop(tp_msg);
+            if (is_pop) {
+                if (tp_msg != NULL) {
+                    //amqp_basic_properties_t 消息数据的基本属性,里面有15个成员.
+                    amqp_basic_properties_t props;
+
+                    //判断是否要设置发送消息的超时时间, 如果配置10秒,超时后,服务器会自动删除消息
+                    if (tp_msg->m_timeout_ms == std::chrono::milliseconds(0)) {
+                        //amqp_flags_t _flags	一个uint32_t, 按位 表示这15个属性的修改开关.
+                        //例如:     _flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG = 0b 1001 0000 0000 0000;
+                        //就表示   content-type  和  delivery-mode  是有效属性. 接下来的设置就会生效.
+                        props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG;
+                        //amqp_bytes_t content_type 消息数据的类型 "text/plain"是 普通文本格式
+                        //注意了,需要使用 amqp_cstring_bytes() 将char*转为amqp_bytes_t(自定义的字符串, 类似于std::string)
+                        props.content_type = amqp_cstring_bytes("text/plain");
+                        //uint8_t delivery_mode 配送模式  2表示持续发送模式
+                        props.delivery_mode = AMQP_DELIVERY_PERSISTENT;
+                    } else {
+                        //amqp_flags_t _flags	一个uint32_t, 按位 表示这15个属性的修改开关.
+                        //例如:     _flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG = 0b 1001 0000 0000 0000;
+                        //就表示   content-type  和  delivery-mode  是有效属性. 接下来的设置就会生效.
+                        props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG |
+                                       AMQP_BASIC_EXPIRATION_FLAG;
+                        //amqp_bytes_t content_type 消息数据的类型 "text/plain"是 普通文本格式
+                        //注意了,需要使用 amqp_cstring_bytes() 将char*转为amqp_bytes_t(自定义的字符串, 类似于std::string)
+                        props.content_type = amqp_cstring_bytes("text/plain");
+                        //uint8_t delivery_mode 配送模式  2表示持续发送模式
+                        props.delivery_mode = AMQP_DELIVERY_PERSISTENT;
+                        char buf[256] = {0};
+                        sprintf(buf, "%d", (int) tp_msg->m_timeout_ms.count());
+                        props.expiration = amqp_cstring_bytes(buf);//超时, 单位ms;
+                    }
+
+                    {//这个大括号表示只对 recv 和 send 加锁, 不要因为后面的复杂逻辑影响通信效率
+                        std::unique_lock<std::mutex> lk(m_mutex);
+//						std::cout << " huli test :::: " << " tp_msg->m_message_buf = " << tp_msg->m_message_buf << std::endl;
+
+                        //amqp_basic_publish() 发布消息给代理服务器, 在交换器上发布一个带有路由密钥的消息。交换机会根据路由密钥匹配,放到对应的队列里面
+                        //输入 amqp_connection_state_t state 连接状态参数的结构体
+                        //输入 amqp_channel_t channel 连接通道的编号
+                        //输入 amqp_bytes_t exchange 交换机模式字符串
+                        //输入 amqp_bytes_t routing_key 路由密钥字符串, 交换机的判断规则. 发送端的 routingkey 和 接收端的 bindingkey 需要保持一致
+                        //输入 amqp_boolean_t mandatory 强制服务器必须通过路由密钥才能存到队列, 默认为0
+                        //输入 amqp_boolean_t immediate 表示服务器必须立刻转发消息给接受者, 默认为0
+                        //输入 struct amqp_basic_properties_t_ const *properties 消息数据的基本属性
+                        //输入 amqp_bytes_t body 消息数据内容
+                        //返回错误码 成功返回AMQP_STATUS_OK = 0x0, 失败返回错误状态码, 详见 enum amqp_status_enum_
+                        //注注注注注意了::amqp_basic_publish()是异步通信,
+                        // return AMQP_STATUS_OK 也只是表示消息成功发送到服务器. 无法确认 接收端是否正常接受消息
+                        t_result = amqp_basic_publish(mp_connect, tp_msg->m_channel,
+                                                      amqp_cstring_bytes(tp_msg->m_exchange_name.c_str()),
+                                                      amqp_cstring_bytes(tp_msg->m_routing_key.c_str()), 0, 0,
+                                                      &props, amqp_cstring_bytes(tp_msg->m_message_buf.c_str()));
+                    }
+
+
+                    if (t_result == AMQP_STATUS_OK) {
+                        m_rabbitmq_status = RABBITMQ_STATUS_READY;
+                        delete (tp_msg);
+                        tp_msg = NULL;
+//							std::string re = amqp_error_to_string(t_result, "amqp_basic_publish");
+//							std::cout << " huli test :::: " << " re = " << re << std::endl;
+//							return Error_manager(Error_code::RABBITMQ_AMQP_BASIC_PUBLISH_ERROR, Error_level::MINOR_ERROR,
+//												 amqp_error_to_string(t_result, "amqp_basic_publish") );
+                    } else {
+                        std::string re = amqp_error_to_string(t_result, "amqp_basic_publish");
+                        std::cout << " huli test :::: " << " re = " << re << std::endl;
+
+                        //重启
+                        m_rabbitmq_status = RABBITMQ_STATUS_RECONNNECT;
+                        m_send_list.push(tp_msg);    //重新加入队列,下一次再发
+                        tp_msg = NULL;
+                        rabbitmq_reconnnect();
+                    }
+
+
+                }
+            } else {
+                //没有取出, 那么应该就是 m_termination_flag 结束了
+//				return Error_manager(Error_code::CONTAINER_IS_TERMINATE, Error_level::MINOR_ERROR,
+//									 " Communication_socket_base::send_data_thread() error ");
+            }
+        }
+    }
+
+    LOG(INFO) << " Rabbitmq_base::send_thread end " << this;
+    return;
+}
+
+//手动封装消息,需要手动写入参数channel,exchange_name,routing_key
+Error_manager
+Rabbitmq_base::encapsulate_msg(std::string message, int channel, std::string exchange_name, std::string routing_key,
+                               int timeout_ms = 0) {
+    if (m_rabbitmq_status != RABBITMQ_STATUS_READY) {
+        LOG(ERROR) << " m_rabbitmq_status error ";
+        return Error_manager(Error_code::ERROR, Error_level::MINOR_ERROR,
+                             " m_rabbitmq_status error ");
+    }
+//    LOG(INFO) << exchange_name << " " << routing_key;
+    Rabbitmq_message *tp_msg = new Rabbitmq_message(message, channel, exchange_name, routing_key, timeout_ms);
+    bool is_push = m_send_list.push(tp_msg);
+    if (is_push == false) {
+        delete (tp_msg);
+        tp_msg = NULL;
+        return Error_manager(Error_code::CONTAINER_IS_TERMINATE, Error_level::MINOR_ERROR,
+                             " Communication_socket_base::encapsulate_msg error ");
+    }
+    return Error_code::SUCCESS;
+}
+
+//手动封装消息,需要手动写入参数channel,exchange_name,routing_key
+Error_manager Rabbitmq_base::encapsulate_msg(Rabbitmq_message *p_msg) {
+    Rabbitmq_message *tp_msg = new Rabbitmq_message(*p_msg);
+    bool is_push = m_send_list.push(tp_msg);
+    if (is_push == false) {
+        delete (tp_msg);
+        tp_msg = NULL;
+        return Error_manager(Error_code::CONTAINER_IS_TERMINATE, Error_level::MINOR_ERROR,
+                             " Communication_socket_base::encapsulate_msg error ");
+    }
+    return Error_code::SUCCESS;
+}
+
+//手动封装任务消息(请求和答复), 系统会使用rabbitmq.proto的配置参数,
+Error_manager Rabbitmq_base::encapsulate_task_msg(std::string message, int vector_index) {
+    int channel = m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_request_vector(vector_index).channel();
+    std::string exchange_name = m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_request_vector(
+            vector_index).exchange_name();
+    std::string routing_key = m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_request_vector(
+            vector_index).routing_key();
+    int timeout_ms = m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_request_vector(
+            vector_index).timeout_ms();
+    Rabbitmq_message *tp_msg = new Rabbitmq_message(message, channel, exchange_name, routing_key, timeout_ms);
+    bool is_push = m_send_list.push(tp_msg);
+    if (is_push == false) {
+        delete (tp_msg);
+        tp_msg = NULL;
+        return Error_manager(Error_code::CONTAINER_IS_TERMINATE, Error_level::MINOR_ERROR,
+                             " Communication_socket_base::encapsulate_msg error ");
+    }
+    return Error_code::SUCCESS;
+}
+
+//手动封装状态消息, 系统会使用rabbitmq.proto的配置参数,
+Error_manager Rabbitmq_base::encapsulate_status_msg(std::string message, int vector_index) {
+    int channel = m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_status_vector(vector_index).channel();
+    std::string exchange_name = m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_status_vector(
+            vector_index).exchange_name();
+    std::string routing_key = m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_status_vector(
+            vector_index).routing_key();
+    int timeout_ms = m_rabbitmq_parameter_all.rabbitmq_parameters().rabbitmq_sender_status_vector(
+            vector_index).timeout_ms();
+    Rabbitmq_message *tp_msg = new Rabbitmq_message(message, channel, exchange_name, routing_key, timeout_ms);
+    bool is_push = m_send_list.push(tp_msg);
+    if (is_push == false) {
+        delete (tp_msg);
+        tp_msg = NULL;
+        return Error_manager(Error_code::CONTAINER_IS_TERMINATE, Error_level::MINOR_ERROR,
+                             " Communication_socket_base::encapsulate_msg error ");
+    }
+    return Error_code::SUCCESS;
+}
+
+//mp_encapsulate_stauts_thread 自动封装线程执行函数,
+void Rabbitmq_base::encapsulate_status_thread() {
+    LOG(INFO) << " Rabbitmq_base::encapsulate_status_thread start " << this;
+
+    //通信封装线程, 负责定时封装消息, 并存入 m_send_data_list
+    while (m_encapsulate_status_condition.is_alive()) {
+        bool t_pass_flag = m_encapsulate_status_condition.wait_for_millisecond(m_encapsulate_status_cycle_time);
+
+        if (m_encapsulate_status_condition.is_alive()) {
+            std::this_thread::yield();
+            //如果封装线程被主动唤醒, 那么就表示 需要主动发送消息,
+            if (t_pass_flag) {
+                //主动发送消息,
+            }
+                //如果封装线程超时通过, 那么就定时封装心跳和状态信息
+            else {
+                //只有通信正常的时候,才封装发送状态消息
+                if (m_rabbitmq_status == RABBITMQ_STATUS_READY) {
+                    auto_encapsulate_status();
+                }
+            }
+        }
+    }
+
+    LOG(INFO) << " Rabbitmq_base::encapsulate_status_thread end " << this;
+    return;
+}
+
+//定时封装发送消息, 一般为心跳和状态信息, 需要子类重载
+Error_manager Rabbitmq_base::auto_encapsulate_status() {
+    if (encapsulate_status_callback != NULL) {
+        return encapsulate_status_callback();
+    }
+    return Error_code::SUCCESS;
+}
+
+
+//把rabbitmq的错误信息转化为string, amqp_status就是enum amqp_status_enum_, amqp_error_string2()函数可以把他翻译为string
+std::string Rabbitmq_base::amqp_error_to_string(int amqp_status) {
+    char buf[256] = {0};
+    sprintf(buf, "amqp_status = 0x%x, %s", amqp_status, amqp_error_string2(amqp_status));
+    return buf;
+}
+
+//把rabbitmq的错误信息转化为string, amqp_status就是enum amqp_status_enum_, amqp_error_string2()函数可以把他翻译为string
+std::string Rabbitmq_base::amqp_error_to_string(int amqp_status, std::string amqp_fun_name) {
+    char buf[256] = {0};
+    sprintf(buf, "amqp_fun_name = %s, amqp_status = 0x%x, %s", amqp_fun_name.c_str(), amqp_status,
+            amqp_error_string2(amqp_status));
+    return buf;
+}
+
+//把rabbitmq的错误信息转化为string, amqp_rpc_reply_t就是amqp函数运行的结果
+std::string Rabbitmq_base::amqp_error_to_string(amqp_rpc_reply_t amqp_rpc_reply) {
+    char buf[256] = {0};
+    //	amqp_response_type_enum reply_type 登录成功是 AMQP_RESPONSE_NORMAL
+    //		失败:如果是 reply_type == AMQP_RESPONSE_SERVER_EXCEPTION, 服务器连接错误, 错误信息在 amqp_method_t reply
+    //		失败:如果是 reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION, 库函数错误, 错误信息在 int library_error
+    switch (amqp_rpc_reply.reply_type) {
+        case AMQP_RESPONSE_NORMAL: {
+            sprintf(buf, "SUCCESS");
+            break;
+        }
+        case AMQP_RESPONSE_NONE: {
+            sprintf(buf, " reply_type = AMQP_RESPONSE_NONE ");
+            break;
+        }
+        case AMQP_RESPONSE_LIBRARY_EXCEPTION: {
+            sprintf(buf, " reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION, library_error = %s, ",
+                    amqp_error_string2(amqp_rpc_reply.library_error));
+            break;
+        }
+        case AMQP_RESPONSE_SERVER_EXCEPTION: {
+            if (amqp_rpc_reply.reply.id == AMQP_CONNECTION_CLOSE_METHOD) {
+                amqp_connection_close_t *p_decoded = (amqp_connection_close_t *) amqp_rpc_reply.reply.decoded;
+                sprintf(buf, " reply.id = AMQP_CONNECTION_CLOSE_METHOD, reply = %u, %.*s ",
+                        p_decoded->reply_code, (int) p_decoded->reply_text.len, (char *) p_decoded->reply_text.bytes);
+            } else if (amqp_rpc_reply.reply.id == AMQP_CHANNEL_CLOSE_METHOD) {
+                amqp_channel_close_t *p_decoded = (amqp_channel_close_t *) amqp_rpc_reply.reply.decoded;
+                sprintf(buf, " reply.id = AMQP_CHANNEL_CLOSE_METHOD, reply = %u, %.*s ",
+                        p_decoded->reply_code, (int) p_decoded->reply_text.len, (char *) p_decoded->reply_text.bytes);
+            } else {
+                sprintf(buf, " reply_type = AMQP_RESPONSE_SERVER_EXCEPTION ");
+            }
+            break;
+        }
+        default: {
+            sprintf(buf, " reply_type = unknown, reply.id = 0x%08X, ",
+                    amqp_rpc_reply.reply.id);
+            break;
+        }
+    }
+
+    return buf;
+}
+
+//把rabbitmq的错误信息转化为string, amqp_rpc_reply_t就是amqp函数运行的结果
+std::string Rabbitmq_base::amqp_error_to_string(amqp_rpc_reply_t amqp_rpc_reply, std::string amqp_fun_name) {
+    char buf[256] = {0};
+    //	amqp_response_type_enum reply_type 登录成功是 AMQP_RESPONSE_NORMAL
+    //		失败:如果是 reply_type == AMQP_RESPONSE_SERVER_EXCEPTION, 服务器连接错误, 错误信息在 amqp_method_t reply
+    //		失败:如果是 reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION, 库函数错误, 错误信息在 int library_error
+    switch (amqp_rpc_reply.reply_type) {
+        case AMQP_RESPONSE_NORMAL: {
+            sprintf(buf, "SUCCESS");
+            break;
+        }
+        case AMQP_RESPONSE_NONE: {
+            sprintf(buf, "amqp_fun_name = %s, reply_type = AMQP_RESPONSE_NONE ", amqp_fun_name.c_str());
+            break;
+        }
+        case AMQP_RESPONSE_LIBRARY_EXCEPTION: {
+            // huli test 123123123::::  error_description = amqp_fun_name = amqp_consume_message, reply_type = AMQP_RESPONSE_LIBRARY_EXCEPTION, library_error = unexpected protocol state,
+            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));
+            break;
+        }
+        case AMQP_RESPONSE_SERVER_EXCEPTION: {
+            if (amqp_rpc_reply.reply.id == AMQP_CONNECTION_CLOSE_METHOD) {
+                amqp_connection_close_t *p_decoded = (amqp_connection_close_t *) amqp_rpc_reply.reply.decoded;
+                sprintf(buf, "amqp_fun_name = %s, reply.id = AMQP_CONNECTION_CLOSE_METHOD, reply = %u, %.*s ",
+                        amqp_fun_name.c_str(), p_decoded->reply_code, (int) p_decoded->reply_text.len,
+                        (char *) p_decoded->reply_text.bytes);
+            } else if (amqp_rpc_reply.reply.id == AMQP_CHANNEL_CLOSE_METHOD) {
+                amqp_channel_close_t *p_decoded = (amqp_channel_close_t *) amqp_rpc_reply.reply.decoded;
+                sprintf(buf, "amqp_fun_name = %s, reply.id = AMQP_CHANNEL_CLOSE_METHOD, reply = %u, %.*s ",
+                        amqp_fun_name.c_str(), p_decoded->reply_code, (int) p_decoded->reply_text.len,
+                        (char *) p_decoded->reply_text.bytes);
+            } else {
+                sprintf(buf, "amqp_fun_name = %s, reply_type = AMQP_RESPONSE_SERVER_EXCEPTION ", amqp_fun_name.c_str());
+            }
+            break;
+        }
+        default: {
+            sprintf(buf, "amqp_fun_name = %s, reply_type = unknown, reply.id = 0x%08X, ",
+                    amqp_fun_name.c_str(), amqp_rpc_reply.reply.id);
+            break;
+        }
+    }
+
+    return buf;
+}
+
+
+

+ 207 - 0
include/rabbitmq/rabbitmq_base.h

@@ -0,0 +1,207 @@
+/*
+ * rabbitmq_base 通信模块的基类,
+ * 用户从这个基类继承, 初始化之后, 便可以自动进行通信
+ * 重载解析消息和封装消息,
+
+ nanosmg 必须实时接受消息, 如果不收可能就丢包, 所以本地开启了接受线程和解析线程.
+ 	接受线程实时接受,然后缓存到本地list, 然后解析线程再慢慢处理.
+ rabbitmq 的服务器可以缓存消息, 如果子节点不接受, 数据仍然留在服务器上, 在需要的时候再去接受,不会丢包.
+ 	因此删除了接受线程和缓存list, 直接使用解析线程,一边接受一边处理,处理完后再接受下一条.
+
+ * */
+
+#ifndef __RIBBITMQ_BASE__HH__
+#define __RIBBITMQ_BASE__HH__
+
+#include <mutex>
+#include <thread>
+
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <map>
+#include "protobuf/load_protobuf.hpp"
+
+#include <rabbitmq-c/amqp.h>
+#include <rabbitmq-c/tcp_socket.h>
+#include <cassert>
+
+#include <glog/logging.h>
+#include "error_code/error_code.hpp"
+#include "thread/binary_buf.h"
+#include "thread/thread_safe_list.hpp"
+#include "thread/thread_condition.h"
+
+#include "rabbitmq/rabbitmq.pb.h"
+#include "rabbitmq/rabbitmq_message.h"
+
+//rabbitmq初始化配置参数的默认路径
+#define RABBITMQ_PARAMETER_PATH "../etc/rabbitmq.prototxt"
+//amqp_basic_qos设置通道每次只能接受PREFETCH_COUNT条消息, 默认每次只能同时接受1条消息
+#define PREFETCH_COUNT 1
+
+class Rabbitmq_base {
+    //通信状态
+    enum Rabbitmq_status {
+        RABBITMQ_STATUS_UNKNOW = 0,                //通信状态 未知
+        RABBITMQ_STATUS_READY = 1,                //通信状态 正常
+        RABBITMQ_STATUS_DISCONNECT = 11,                //通信状态 断连(可能会在断连和重连之间反复跳动)
+        RABBITMQ_STATUS_RECONNNECT = 12,                //通信状态 重连(可能会在断连和重连之间反复跳动)
+
+
+        RABBITMQ_STATUS_FAULT = 100,            //通信状态 错误
+    };
+public:
+    struct QueueKey {
+        std::string ex;
+        std::string queue;
+    };
+
+public:
+    Rabbitmq_base();
+
+    Rabbitmq_base(const Rabbitmq_base &other) = delete;
+
+    Rabbitmq_base &operator=(const Rabbitmq_base &other) = delete;
+
+    ~Rabbitmq_base();
+
+public://API functions
+    //初始化 通信 模块。如下三选一
+    Error_manager rabbitmq_init();
+
+    //初始化 通信 模块。从文件读取
+    Error_manager rabbitmq_init_from_protobuf(std::string prototxt_path);
+
+    //初始化 通信 模块。从protobuf读取
+    Error_manager rabbitmq_init_from_protobuf(Rabbitmq_proto::Rabbitmq_parameter_all &rabbitmq_parameter_all);
+
+    //反初始化 通信 模块。
+    Error_manager rabbitmq_uninit();
+
+    //重连, 快速uninit, init
+    Error_manager rabbitmq_reconnnect();
+
+    //手动封装消息, 如下四选一
+    //手动封装消息,需要手动写入参数channel,exchange_name,routing_key
+    Error_manager encapsulate_msg(std::string message, int channel, std::string exchange_name, std::string routing_key,
+                                  int timeout_ms);
+
+    //手动封装消息,需要手动写入参数channel,exchange_name,routing_key
+    Error_manager encapsulate_msg(Rabbitmq_message *p_msg);
+
+    //手动封装任务消息(请求和答复), 系统会使用rabbitmq.proto的配置参数,
+    Error_manager encapsulate_task_msg(std::string message, int vector_index = 0);
+
+    //手动封装状态消息, 系统会使用rabbitmq.proto的配置参数,
+    Error_manager encapsulate_status_msg(std::string message, int vector_index = 0);
+
+    //ack_msg 处理完消息后, 手动确认消息, 通知服务器队列删除消息.
+    //执行者在execute_msg里面可以调用这个函数, 或者回调也行.
+    Error_manager ack_msg(Rabbitmq_message *p_msg);
+
+    //设置 自动封装状态的时间周期, 可选(默认1000ms)
+    void set_encapsulate_status_cycle_time(unsigned int encapsulate_status_cycle_time);
+
+    //设置回调函数check_msg_callback
+    void set_check_msg_callback(Error_manager (*callback)(Rabbitmq_message *p_msg));
+
+    //设置回调函数check_executer_callback
+    void set_check_executer_callback(Error_manager (*callback)(Rabbitmq_message *p_msg));
+
+    //设置回调函数execute_msg_callback
+    void set_execute_msg_callback(Error_manager (*callback)(Rabbitmq_message *p_msg));
+
+    //设置回调函数encapsulate_status_callback
+    void set_encapsulate_status_callback(Error_manager (*callback)());
+
+protected:
+    //创建通道队列消费者, (交换机和永久队列不在代码里创建,请在服务器上手动创建)
+    Error_manager rabbitmq_new_channel_queue_consume(Rabbitmq_proto::Rabbitmq_parameter_all &rabbitmq_parameter_all);
+
+    //启动通信, 开启线程, run thread
+    Error_manager rabbitmq_run();
+
+    //mp_receive_analysis_thread 接受解析 执行函数,
+    void receive_analysis_thread();
+
+    //检查消息是否有效, 主要检查消息类型和接受者, 判断这条消息是不是给我的., 需要子类重载
+    virtual Error_manager check_msg(Rabbitmq_message *p_msg);
+
+    //检查执行者的状态, 判断能否处理这条消息, 需要子类重载
+    virtual Error_manager check_executer(Rabbitmq_message *p_msg);
+
+    //处理消息, 需要子类重载
+    virtual Error_manager execute_msg(Rabbitmq_message *p_msg);
+
+    //mp_send_thread 发送线程执行函数,
+    void send_thread();
+
+    //mp_encapsulate_stauts_thread 自动封装线程执行函数,
+    void encapsulate_status_thread();
+
+    //定时封装发送消息, 一般为心跳和状态信息, 需要子类重载
+    virtual Error_manager auto_encapsulate_status();
+
+protected:
+    //把rabbitmq的错误信息转化为string, amqp_status就是enum amqp_status_enum_, amqp_error_string2()函数可以把他翻译为string
+    std::string amqp_error_to_string(int amqp_status);
+
+    //把rabbitmq的错误信息转化为string, amqp_status就是enum amqp_status_enum_, amqp_error_string2()函数可以把他翻译为string
+    std::string amqp_error_to_string(int amqp_status, std::string amqp_fun_name);
+
+    //把rabbitmq的错误信息转化为string, amqp_rpc_reply_t就是amqp函数运行的结果
+    std::string amqp_error_to_string(amqp_rpc_reply_t amqp_rpc_reply);
+
+    //把rabbitmq的错误信息转化为string, amqp_rpc_reply_t就是amqp函数运行的结果
+    std::string amqp_error_to_string(amqp_rpc_reply_t amqp_rpc_reply, std::string amqp_fun_name);
+
+protected://member variable
+    Rabbitmq_status m_rabbitmq_status;        //通信状态
+
+    //rabbitmq网络通信 连接配置信息
+    Rabbitmq_proto::Rabbitmq_parameter_all m_rabbitmq_parameter_all;
+    amqp_connection_state_t_ *mp_connect;        // 连接参数的结构体, 内存系统自动分配,自动释放
+    amqp_socket_t *mp_socket;        // 网口通信socket, 内存系统自动分配,自动释放
+    std::string m_ip;            //服务器ip地址, 不带端口
+    int m_port;            //端口,默认5672
+    std::string m_user;            //用户名, 默认guest
+    std::string m_password;        //密码, 默认guest
+    std::mutex m_mutex;        // socket的锁, 发送和接受的通信锁
+    std::map<int, bool> m_channel_map;    // 通道的缓存,防止重复开启
+
+    // rabbitmq发送队列map
+    std::map<const std::string, Rabbitmq_proto::Rabbitmq_channel_queue_consume> mp_rabbitmq_reciever;
+    std::map<const std::string, Rabbitmq_proto::Rabbitmq_channel_queue_consume> mp_rabbitmq_sender_request;
+    std::map<const std::string, Rabbitmq_proto::Rabbitmq_channel_queue_consume> mp_rabbitmq_sender_status;
+
+    //接受模块,
+    //rabbitmq 的服务器可以缓存消息, 如果子节点不接受, 数据仍然留在服务器上, 在需要的时候再去接受,不会丢包.
+    //因此删除了接受线程和缓存list, 直接使用解析线程,一边接受一边处理,处理完后再接受下一条.
+    std::thread *mp_receive_analysis_thread;                //接受解析的线程指针
+    Thread_condition m_receive_analysis_condition;            //接受解析的条件变量
+
+    //发送模块,
+    Thread_safe_list<Rabbitmq_message *> m_send_list;                //发送的list容器
+    std::thread *mp_send_thread;                //发送的线程指针
+    Thread_condition m_send_condition;            //发送的条件变量
+    //自动发送状态的
+    std::thread *mp_encapsulate_status_thread;            //自动封装状态的线程指针
+    Thread_condition m_encapsulate_status_condition;            //自动封装状态的条件变量
+    unsigned int m_encapsulate_status_cycle_time;        //自动封装状态的时间周期
+
+    //回调函数,
+    // //可以选择设置回调函数,或者子类继承重载,二选一.
+    Error_manager (*check_msg_callback)(Rabbitmq_message *p_msg);
+
+    Error_manager (*check_executer_callback)(Rabbitmq_message *p_msg);
+
+    Error_manager (*execute_msg_callback)(Rabbitmq_message *p_msg);
+
+    Error_manager (*encapsulate_status_callback)();
+};
+
+
+#endif //__RIBBITMQ_BASE__HH__

+ 99 - 0
include/rabbitmq/rabbitmq_message.cpp

@@ -0,0 +1,99 @@
+#include "rabbitmq_message.h"
+
+
+Rabbitmq_message::Rabbitmq_message() {
+    m_message_type = message::Message_type::eBase_msg;
+    m_receive_time = std::chrono::system_clock::now();
+    m_timeout_ms = std::chrono::milliseconds(0);        //超时默认0秒
+    m_sender = message::Communicator::eEmpty;
+    m_receiver = message::Communicator::eEmpty;
+//	m_message_buf = "";
+}
+
+Rabbitmq_message::Rabbitmq_message(const message::Base_info &base_info, std::string receive_string, int channel,
+                                   int delivery_tag, std::string exchange_name, std::string routing_key) {
+    m_message_type = (message::Message_type) (base_info.msg_type());
+
+    m_receive_time = std::chrono::system_clock::now();
+    m_timeout_ms = std::chrono::milliseconds(base_info.timeout_ms());
+    m_sender = (message::Communicator) (base_info.sender());
+    m_receiver = (message::Communicator) (base_info.receiver());
+    m_message_buf = receive_string;
+
+    m_channel = channel;
+    m_delivery_tag = delivery_tag;
+    m_exchange_name = exchange_name;
+    m_routing_key = routing_key;
+}
+
+Rabbitmq_message::Rabbitmq_message(std::string receive_string, int channel, std::string exchange_name,
+                                   std::string routing_key, int timeout_ms = 0) {
+    m_timeout_ms = std::chrono::milliseconds(timeout_ms);
+    m_message_buf = receive_string;
+    m_channel = channel;
+    m_exchange_name = exchange_name;
+    m_routing_key = routing_key;
+}
+
+
+Rabbitmq_message::~Rabbitmq_message() {
+
+}
+
+bool Rabbitmq_message::is_over_time() {
+    if (std::chrono::system_clock::now() - m_receive_time > m_timeout_ms) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+
+void
+Rabbitmq_message::reset(const message::Base_info &base_info, std::string receive_string, int channel, int delivery_tag,
+                        std::string exchange_name, std::string routing_key) {
+    m_message_type = (message::Message_type) (base_info.msg_type());
+
+    m_receive_time = std::chrono::system_clock::now();
+    m_timeout_ms = std::chrono::milliseconds(base_info.timeout_ms());
+    m_sender = (message::Communicator) (base_info.sender());
+    m_receiver = (message::Communicator) (base_info.receiver());
+    m_message_buf = receive_string;
+    m_channel = channel;
+    m_delivery_tag = delivery_tag;
+    m_exchange_name = exchange_name;
+    m_routing_key = routing_key;
+}
+
+void
+Rabbitmq_message::reset(std::string receive_string, int channel, std::string exchange_name, std::string routing_key,
+                        int timeout_ms = 0) {
+    m_timeout_ms = std::chrono::milliseconds(timeout_ms);
+    m_message_buf = receive_string;
+    m_channel = channel;
+    m_exchange_name = exchange_name;
+    m_routing_key = routing_key;
+}
+
+message::Message_type Rabbitmq_message::get_message_type() {
+    return m_message_type;
+}
+
+message::Communicator Rabbitmq_message::get_sender() {
+    return m_sender;
+}
+
+message::Communicator Rabbitmq_message::get_receiver() {
+    return m_receiver;
+}
+
+std::string Rabbitmq_message::get_message_buf() {
+    return m_message_buf;
+}
+
+std::chrono::system_clock::time_point Rabbitmq_message::get_receive_time() {
+    return m_receive_time;
+}
+
+
+

+ 76 - 0
include/rabbitmq/rabbitmq_message.h

@@ -0,0 +1,76 @@
+//
+// Created by huli on 2020/6/29.
+//
+
+#ifndef __RABBITMQ_MESSAGE_H
+#define __RABBITMQ_MESSAGE_H
+
+#include "error_code/error_code.hpp"
+
+#include <time.h>
+#include <sys/time.h>
+#include <chrono>
+//#include <iosfwd>
+
+#include <string>
+#include "message/message_base.pb.h"
+
+class Rabbitmq_message {
+public:
+    Rabbitmq_message();
+
+    Rabbitmq_message(const message::Base_info &base_info, std::string receive_string, int channel, int delivery_tag,
+                     std::string exchange_name, std::string routing_key);
+
+    Rabbitmq_message(std::string receive_string, int channel, std::string exchange_name, std::string routing_key,
+                     int timeout_ms);
+
+    Rabbitmq_message(const Rabbitmq_message &other) = default;
+
+    Rabbitmq_message &operator=(const Rabbitmq_message &other) = default;
+
+    ~Rabbitmq_message();
+
+public://API functions
+    bool is_over_time();
+
+public://get or set member variable
+    void reset(const message::Base_info &base_info, std::string receive_string, int channel, int delivery_tag,
+               std::string exchange_name, std::string routing_key);
+
+    void
+    reset(std::string receive_string, int channel, std::string exchange_name, std::string routing_key, int timeout_ms);
+
+    message::Message_type get_message_type();
+
+    message::Communicator get_sender();
+
+    message::Communicator get_receiver();
+
+    std::string get_message_buf();
+
+    std::chrono::system_clock::time_point get_receive_time();
+
+public://member variable
+    message::Message_type m_message_type;                //消息类型
+    std::chrono::system_clock::time_point m_receive_time;                //接收消息的时间点
+    std::chrono::milliseconds m_timeout_ms;                //超时时间, 整个软件都统一为毫秒
+    message::Communicator m_sender;                    //发送者
+    message::Communicator m_receiver;                    //接受者
+
+    std::string m_message_buf;                //消息数据
+
+    //rabbitmq 接受特有, 保存channel和delivery_tag, 用来ack
+    //rabbitmq 通用, 填写m_channel m_exchange_name m_routing_key 用来区别消息
+    int m_channel;                    //接受消息来源的通道
+    int m_delivery_tag;                //接受消息的传递编号
+    std::string m_exchange_name;            //交换机名称
+    std::string m_routing_key;                //key,识别码
+
+
+private:
+
+};
+
+
+#endif //__RABBITMQ_MESSAGE_H

+ 79 - 0
include/rabbitmq/胡力的rabbitmq-c说明文档.md

@@ -0,0 +1,79 @@
+
+
+安装 rabbitMQ-c 的注意事项:(这里只介绍C语言版本的客户端)
+
+1.代码下载
+	rabbitMQ官网 		https://www.rabbitmq.com/
+	各种语言支持			https://www.rabbitmq.com/devtools.html
+		里面有C/C++的支持
+	github上源码			https://github.com/alanxz/rabbitmq-c
+
+2.安装方式
+	终端指令:注意了,要用sudo使用管理员权限
+	git clone https://github.com/alanxz/rabbitmq-c  
+	cd rabbitmq-c
+	mkdir build
+	cd build
+	sudo cmake ..
+	sudo cmake --build .
+	sudo make 
+	sudo make install
+
+	详情参考		https://blog.csdn.net/caicaiatnbu/article/details/98099779?ops_request_misc=&request_id=&biz_id=102&utm_term=RabbitMQ-C&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-3-98099779.nonecase&spm=1018.2226.3001.4187
+
+	如果提示openssl有报错,卸载并重装openssl
+	详情参考		https://blog.csdn.net/Cai181191/article/details/120648055?ops_request_misc=&request_id=&biz_id=102&utm_term=%E5%8D%B8%E8%BD%BDopenssl&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-120648055.142^v41^pc_rank_34,185^v2^control&spm=1018.2226.3001.4187
+
+3.examples代码编译
+	方案一:不建议
+	打开		./rabbitmq-c/CMakeLists.txt
+		找到		option(BUILD_EXAMPLES "Build Examples" OFF)
+		修改为	option(BUILD_EXAMPLES "Build Examples" ON)
+	然后重新编译 ./rabbitmq-c/CMakeLists.txt  就是把上面第二步再做一遍
+		cd ./rabbitmq-c/build
+		sudo cmake ..
+		sudo cmake --build .
+		sudo make 
+	然后就可以看到	./rabbitmq-c/build/examples 路径下面出现了样例的执行文件
+
+	方案二:强烈推荐
+	进入		./rabbitmq-c/examples 文件夹	,后面的操作都在这个文件夹里面
+	打开		./rabbitmq-c/examples/CMakeLists.txt
+	全局替换		rabbitmq::rabbitmq   改为	rabbitmq
+	就是删除 rabbitmq::
+	然后 编译 ./rabbitmq-c/examples/CMakeLists.txt
+		cd ./rabbitmq-c/examples/
+		mkdir build
+		cd build
+		cmake ..
+		make 
+	然后就可以看到	./rabbitmq-c/examples/build 路径下面出现了样例的执行文件
+
+4.自己开发rabbitMQ-c代码
+	在自己的  CMakeLists.txt  里面 增加系统头文件和库文件的目录.
+	例如:
+		include_directories(
+        /usr/local/include
+		)
+		link_directories("/usr/local/lib")
+
+	在自己的  CMakeLists.txt  里面 target_link_libraries 追加 rabbitmq
+	例如:	
+		target_link_libraries(xxx工程名		rabbitmq )
+
+	具体的函数使用,参考examples里面的amqp_listen.c和amqp_sendstring.c
+
+5.服务器网站配置
+	登录服务器   http://127.0.0.1:15672/     或者     http://192.168.2.39:15672/
+		默认账号密码   guest   guest    (注, guest只能本机访问,其他电脑需要新建账户)
+	
+	终端指令: 使用sudo
+		创建用户 rabbitmqctl add_user admin admin
+		设置管理员 rabbitmqctl set_user_tags admin administrator
+		设置权限  rabbitmqctl set_permissions -p/admin ".*"".*"".*"
+		查看用户  rabbitmqctl list_users
+		详见  https://blog.csdn.net/z446981439/article/details/103634524?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166141324016782388032414%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=166141324016782388032414&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-103634524-null-null.142^v42^pc_rank_34,185^v2^control&utm_term=rabbitmq%20%E7%94%A8%E6%88%B7&spm=1018.2226.3001.4187
+
+		个人建议:只在终端上创建账户,然后使用guest在网站上面配置权限.
+	
+	

+ 1 - 0
include/thread/CMakeLists.txt

@@ -1,5 +1,6 @@
 set(LIBRARY_NAME libthread)
 
+unset(OPTION_ENABLE_TEST_CODE CACHE)
 option(OPTION_ENABLE_TEST_CODE "Whether enable test code." OFF)
 message("<=${LIBRARY_NAME}=> OPTION_ENABLE_TEST_CODE: " ${OPTION_ENABLE_TEST_CODE})
 

+ 13 - 0
protoc.sh

@@ -0,0 +1,13 @@
+#!/bin/bash
+
+files=($(find $1 -type f -name "*.proto"))
+paths=()
+filenames=()
+
+for file in ${files[@]}; do
+    path=$(dirname $file)
+    filename=$(basename $file)
+    paths+=("$path")
+    filenames+=("$filename")
+    protoc -I="$path" $filename --cpp_out="$path"
+done