1166 lines
38 KiB
C++
1166 lines
38 KiB
C++
|
||
/******************************************************************************//**
|
||
* @file CInProcBroker.cpp
|
||
* @brief 消息总线接口库中的,进程内代理
|
||
* @author yikenan
|
||
* @version 1.0
|
||
* @date
|
||
**********************************************************************************/
|
||
|
||
#include "boost/typeof/typeof.hpp"
|
||
#include "boost/asio/ip/host_name.hpp"
|
||
#include "boost/interprocess/detail/os_thread_functions.hpp"
|
||
|
||
#include "lz4.h"
|
||
|
||
#include "pub_logger_api/logger.h"
|
||
|
||
#include "../net_msg_bus_base_api/kmbp_cnt.h"
|
||
|
||
#include "../net_msg_bus_base_api/CMbSubEngine.h"
|
||
#include "../net_msg_bus_base_api/CommonDef.h"
|
||
|
||
#include "CInProcBroker.h"
|
||
|
||
namespace iot_net
|
||
{
|
||
|
||
//< 是否允许通讯器发送数据
|
||
volatile bool g_bCommSendEnable = false;
|
||
|
||
CInProcBroker::SActWorker* CInProcBroker::SActWorker::newActWorker(zsock_t *pActorPipe, SActWorkerInitArg *pArgs)
|
||
{
|
||
//< zmalloc内部使用calloc,开辟的内存都初始化为0值
|
||
SActWorker *self = (SActWorker *)zmalloc(sizeof(SActWorker));
|
||
|
||
self->m_bConnected = false;
|
||
self->m_nSendSeq = 0;
|
||
|
||
{
|
||
//< 获取主机名,原本使用zsys_hostname(),现改为boost的方法,原因:
|
||
//< zsys_hostname() 在使用gethostname()获取到主机名后,
|
||
//< 还会gethostbyname()对获取到的主机名进行验证,此时系统(已验证CentOS 7)默认会使用DNS解析主机名
|
||
//< 若系统设置了一个无效的DNS服务器地址,会等待超时,导致耗时过长
|
||
//< boost::asio::ip::host_name()无此问题,应该是直接返回主机名,没有进行进一步验证
|
||
|
||
try
|
||
{
|
||
//memset(self->m_chHostName, 0, sizeof(self->m_chHostName));
|
||
strncpy(self->m_chHostName, boost::asio::ip::host_name().c_str(), sizeof(self->m_chHostName) - 1);
|
||
|
||
}
|
||
catch (std::exception &e)
|
||
{
|
||
LOGERROR("newActWorker(): %s", e.what());
|
||
assert(false);
|
||
}
|
||
}
|
||
|
||
//memset(self->m_chProcName, 0, sizeof(self->m_chProcName));
|
||
strncpy(self->m_chProcName, pArgs->m_pchProcName, sizeof(self->m_chProcName) - 1);
|
||
|
||
//memset(self->m_chInstName, 0, sizeof(self->m_chInstName));
|
||
strncpy(self->m_chInstName, pArgs->m_pchInstName, sizeof(self->m_chInstName) - 1);
|
||
|
||
self->m_pActorPipe = pActorPipe;
|
||
|
||
//< 初始化m_pSubEng
|
||
self->m_pSubEng = new CMbSubEngine;
|
||
assert(self->m_pSubEng);
|
||
|
||
//< 初始化
|
||
self->m_pCommSet = new boost::unordered_set<std::string>;
|
||
assert(self->m_pCommSet);
|
||
|
||
//< 初始化m_pKmbpMsg
|
||
self->m_pKmbpMsg = kmbp_new();
|
||
assert(self->m_pKmbpMsg);
|
||
|
||
//< 初始化m_pSockInCmd
|
||
self->m_pSockInCmd = zsock_new_router(MB_P2C_CMD_ENDPOINT);
|
||
assert(self->m_pSockInCmd);
|
||
|
||
//< 初始化m_pSockInData
|
||
{
|
||
self->m_pSockInData = zsock_new(ZMQ_ROUTER);
|
||
assert(self->m_pSockInData);
|
||
|
||
//< 在zmq 4.1.x版本,高水位设置对下一次bind、connect起效
|
||
//< 4.2.x版本,可以先bind、connect再修改高水位
|
||
|
||
//< Router,发送高水位设大一些,防止丢弃
|
||
zsock_set_sndhwm(self->m_pSockInData, 1000000);
|
||
|
||
//< 由于发送的是指针,不允许router静默丢弃消息,以防内存泄漏
|
||
zsock_set_router_mandatory(self->m_pSockInData, 1);
|
||
|
||
//< 设置收发超时时间,防止本线程持续阻塞,单位ms
|
||
zsock_set_sndtimeo(self->m_pSockInData, 100);
|
||
zsock_set_rcvtimeo(self->m_pSockInData, 100);
|
||
|
||
int nRc = zsock_bind(self->m_pSockInData, MB_P2C_DATA_ENDPOINT);
|
||
assert(0 == nRc);
|
||
}
|
||
|
||
//< 初始化m_pSockOut
|
||
{
|
||
self->m_pSockOut = zsock_new(ZMQ_DEALER);
|
||
assert(self->m_pSockOut);
|
||
|
||
if (pArgs->m_bAddPid)
|
||
{
|
||
self->m_nPid = boost::interprocess::ipcdetail::get_current_process_id();
|
||
}
|
||
else
|
||
self->m_nPid = -1;
|
||
|
||
//< pchIdentity需释放
|
||
char *pchIdentity = zsys_sprintf("%s@%s@%d",
|
||
self->m_chProcName,
|
||
self->m_chInstName,
|
||
self->m_nPid);
|
||
|
||
zsock_set_identity(self->m_pSockOut, pchIdentity);
|
||
zstr_free(&pchIdentity);
|
||
|
||
zsock_set_sndhwm(self->m_pSockOut, 10000);
|
||
zsock_set_rcvhwm(self->m_pSockOut, 100000);
|
||
|
||
//< 设置收发超时时间,防止本线程持续阻塞,单位ms
|
||
zsock_set_sndtimeo(self->m_pSockOut, 100);
|
||
zsock_set_rcvtimeo(self->m_pSockOut, 100);
|
||
|
||
zsock_set_reconnect_ivl(self->m_pSockOut, 500);
|
||
zsock_set_reconnect_ivl_max(self->m_pSockOut, 1000);
|
||
}
|
||
|
||
//< 初始化m_pSockOutMon
|
||
{
|
||
//< pchEndpoint需释放
|
||
char *pchEndpoint = zsys_sprintf("inproc://zmonitor-%p", self->m_pSockOut);
|
||
assert(pchEndpoint);
|
||
|
||
const int nEvent = ZMQ_EVENT_CONNECTED | ZMQ_EVENT_DISCONNECTED | ZMQ_EVENT_MONITOR_STOPPED;
|
||
int nRc = zmq_socket_monitor(zsock_resolve(self->m_pSockOut), pchEndpoint, nEvent);
|
||
assert(0 == nRc);
|
||
|
||
self->m_pSockOutMon = zsock_new(ZMQ_PAIR);
|
||
assert(self->m_pSockOutMon);
|
||
|
||
nRc = zsock_connect(self->m_pSockOutMon, pchEndpoint);
|
||
assert(0 == nRc);
|
||
|
||
//< 释放
|
||
zstr_free(&pchEndpoint);
|
||
}
|
||
|
||
//< 设置m_pSockOut连接
|
||
{
|
||
const int nRc = zsock_connect(self->m_pSockOut, MB_H2P_ENDPOINT);
|
||
assert(0 == nRc);
|
||
}
|
||
|
||
//< 初始化m_pLoop
|
||
{
|
||
self->m_pLoop = zloop_new();
|
||
assert(self->m_pLoop);
|
||
|
||
//< 设置m_pLoop事件驱动,优先级与书写顺序有关
|
||
|
||
//< 周期性循环任务定时器,1s一次,定时器ID从0开始
|
||
int nRc = zloop_timer(self->m_pLoop, 1000, 0, handleCycTaskTimer, self);
|
||
assert(nRc >= 0);
|
||
|
||
bool bRc = setSocketHandle(self, self->m_pActorPipe, handleActorPipe);
|
||
assert(bRc);
|
||
|
||
bRc = setSocketHandle(self, self->m_pSockOutMon, handleSockOutMon);
|
||
assert(bRc);
|
||
|
||
bRc = setSocketHandle(self, self->m_pSockInCmd, handleSockInCmd);
|
||
assert(bRc);
|
||
|
||
bRc = setSocketHandle(self, self->m_pSockInData, handleSockInData);
|
||
assert(bRc);
|
||
|
||
bRc = setSocketHandle(self, self->m_pSockOut, handleSockOut);
|
||
assert(bRc);
|
||
|
||
//< 系统信号打断不退出
|
||
zloop_set_nonstop(self->m_pLoop, true);
|
||
}
|
||
|
||
return self;
|
||
}
|
||
|
||
|
||
void CInProcBroker::SActWorker::destroyActWorker(SActWorker **pSelf)
|
||
{
|
||
if (*pSelf)
|
||
{
|
||
SActWorker *self = *pSelf;
|
||
|
||
delete self->m_pSubEng;
|
||
self->m_pSubEng = NULL;
|
||
|
||
if (self->m_pCommSet)
|
||
{
|
||
if (!(self->m_pCommSet->empty()))
|
||
{
|
||
//< 尚有通讯器未注销
|
||
LOGERROR("destroyActWorker(): please deconstruct all communicator befor releaseMsgBus() !");
|
||
}
|
||
|
||
delete self->m_pCommSet;
|
||
self->m_pCommSet = NULL;
|
||
}
|
||
|
||
zloop_destroy(&(self->m_pLoop));
|
||
|
||
zsock_destroy(&(self->m_pSockInCmd));
|
||
zsock_destroy(&(self->m_pSockInData));
|
||
|
||
//< 取消监视应先于销毁连接到监视(即接收监视消息)的 ZMQ_PAIR 连接,即 m_pSockOutMon
|
||
//< 否则,取消监视时,zeromq 内部发送监视状态消息时可能阻塞,sndtimeo默认值为永久等待
|
||
//< 当被监视的连接销毁时,会自动取消监视
|
||
//< 所以如果不主动取消监视,应当先销毁被监视连接 m_pSockOut ,再销毁接收监视连接 m_pSockOutMon
|
||
zmq_socket_monitor(zsock_resolve(self->m_pSockOut), NULL, 0);
|
||
|
||
zsock_destroy(&(self->m_pSockOut));
|
||
|
||
zsock_destroy(&(self->m_pSockOutMon));
|
||
|
||
kmbp_destroy(&(self->m_pKmbpMsg));
|
||
|
||
free(self);
|
||
*pSelf = NULL;
|
||
}
|
||
}
|
||
|
||
|
||
void CInProcBroker::SActWorker::actorMain(zsock_t *pActorPipe, void *pArgs)
|
||
{
|
||
/* zactor的要求:
|
||
An actor function MUST call zsock_signal (pipe) when initialized
|
||
and MUST listen to pipe and exit on $TERM command.
|
||
*/
|
||
|
||
zsock_signal(pActorPipe, 0);
|
||
|
||
SActWorker *self = newActWorker(pActorPipe, (SActWorkerInitArg *)pArgs);
|
||
if (self)
|
||
{
|
||
zsock_send(pActorPipe, "i", 1);
|
||
|
||
//< 允许通讯器发送数据
|
||
g_bCommSendEnable = true;
|
||
|
||
//< 进入zloop处理,任意zloop函数返回-1,则zloop退出
|
||
zloop_start(self->m_pLoop);
|
||
|
||
destroyActWorker(&self);
|
||
}
|
||
else
|
||
{
|
||
LOGERROR("newActWorker() failed !");
|
||
zsock_send(pActorPipe, "i", 0);
|
||
}
|
||
}
|
||
|
||
|
||
bool CInProcBroker::SActWorker::setSocketHandle(SActWorker *self, zsock_t *pSock, zloop_reader_fn pHandleFuc)
|
||
{
|
||
//if (NULL == self || NULL == pSock)
|
||
// return false;
|
||
|
||
if (NULL != pHandleFuc)
|
||
{
|
||
const int nRc = zloop_reader(self->m_pLoop, pSock, pHandleFuc, self);
|
||
|
||
if (0 != nRc)
|
||
return false;
|
||
|
||
zloop_reader_set_tolerant(self->m_pLoop, pSock);
|
||
}
|
||
else
|
||
zloop_reader_end(self->m_pLoop, pSock);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
bool CInProcBroker::SActWorker::sendOut(SActWorker *self, kmbp_t *pKmbp)
|
||
{
|
||
//if (NULL == self)
|
||
// return false;
|
||
|
||
const int nMsgID = kmbp_id(pKmbp);
|
||
switch ( nMsgID )
|
||
{
|
||
case KMBP_C2H_DATA_DOMAIN:
|
||
case KMBP_C2H_DATA_PEER:
|
||
case KMBP_C2H_DATA_HOST:
|
||
case KMBP_P2H_HEARTBEAT:
|
||
case KMBP_P2H_SUB_ALL:
|
||
case KMBP_P2H_SUB_ADD:
|
||
case KMBP_P2H_SUB_DEL:
|
||
break;
|
||
default:
|
||
{
|
||
LOGERROR("sendOut(): Unexpected message ID = %d ", nMsgID);
|
||
}
|
||
break;
|
||
}
|
||
|
||
self->m_nSendSeq++;
|
||
|
||
kmbp_set_seqno(pKmbp, self->m_nSendSeq);
|
||
|
||
if (0 != kmbp_send(pKmbp, self->m_pSockOut, NULL, NULL))
|
||
{
|
||
LOGWARN("sendOut(): kmbp_send() failed !");
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
void CInProcBroker::SActWorker::decompressData(kmbp_t *pKmbp)
|
||
{
|
||
const int nSizeDst = kmbp_data_unzipsize(pKmbp);
|
||
if (nSizeDst <= 0)
|
||
{
|
||
//< 消息未压缩
|
||
return;
|
||
}
|
||
|
||
zchunk_t *pChunkSrc = kmbp_data_content(pKmbp);
|
||
if (NULL == pChunkSrc)
|
||
{
|
||
//< 启用了压缩,但是却没有数据,不可能
|
||
LOGERROR("decompressData(): NULL == pChunkSrc , some thing wrong !");
|
||
return;
|
||
}
|
||
|
||
const size_t nSizeSrc = zchunk_size(pChunkSrc);
|
||
if (0 == nSizeSrc)
|
||
{
|
||
//< 启用了压缩,但是消息长度为0,不可能
|
||
LOGERROR("decompressData(): 0 == nSizeSrc , some thing wrong !");
|
||
return;
|
||
}
|
||
|
||
if (nSizeSrc >= 2147483647)
|
||
{
|
||
LOGERROR("decompressData(): nSizeSrc >= 2147483647 , too big to decompress !");
|
||
return;
|
||
}
|
||
|
||
//< 注意:失败需释放 pChunkDst
|
||
zchunk_t *pChunkDst = zchunk_new(NULL, nSizeDst);
|
||
|
||
const int nUnzipSize = LZ4_decompress_safe((const char *)zchunk_data(pChunkSrc),
|
||
(char *)zchunk_data(pChunkDst),
|
||
(int)nSizeSrc, nSizeDst);
|
||
|
||
if (nUnzipSize <= 0)
|
||
{
|
||
LOGERROR("LZ4_decompress_safe() failed !");
|
||
zchunk_destroy(&pChunkDst); //< 释放
|
||
return;
|
||
}
|
||
|
||
if (nSizeDst != nUnzipSize)
|
||
{
|
||
LOGERROR("decompressData(): nSizeDst != nUnzipSize , some thing wrong !");
|
||
zchunk_destroy(&pChunkDst); //< 释放
|
||
return;
|
||
}
|
||
|
||
//< 设置 pChunkDst 的实际长度,new时传入的是最大长度
|
||
zchunk_set(pChunkDst, NULL, nUnzipSize);
|
||
|
||
kmbp_set_data_unzipsize(pKmbp, 0);
|
||
kmbp_set_data_content(pKmbp, &pChunkDst);
|
||
}
|
||
|
||
|
||
int CInProcBroker::SActWorker::handleActorPipe(zloop_t *, zsock_t *reader, void *arg)
|
||
{
|
||
SActWorker *self = (SActWorker *)arg;
|
||
|
||
assert(reader == self->m_pActorPipe);
|
||
|
||
bool bTerm = false;
|
||
|
||
for (int i = 0;
|
||
(i < 10) && (zsock_events(reader) & ZMQ_POLLIN);
|
||
i++)
|
||
{
|
||
//< 注意:pchCmd需要释放
|
||
char *pchCmd = zstr_recv(reader);
|
||
|
||
if (NULL == pchCmd)
|
||
{
|
||
//< 有可能是被系统信号打断,不停止
|
||
continue;
|
||
}
|
||
|
||
if (streq(pchCmd, "$TERM"))
|
||
{
|
||
//< zactor要求接收"$TERM"消息,并退出
|
||
|
||
g_bCommSendEnable = false;
|
||
|
||
zclock_sleep(300);
|
||
|
||
//< 释放所有未接收消息
|
||
while (zsock_events(self->m_pSockInData) & ZMQ_POLLIN)
|
||
{
|
||
kmbp_cnt_t *pKmbpCnt = NULL;
|
||
|
||
if (0 != zsock_recv(self->m_pSockInData, "p", &pKmbpCnt))
|
||
continue;
|
||
|
||
//< 有可能为NULL
|
||
if (NULL != pKmbpCnt)
|
||
{
|
||
//< 释放引用
|
||
kmbp_cnt_dec(&pKmbpCnt);
|
||
}
|
||
}
|
||
|
||
bTerm = true;
|
||
}
|
||
else if (streq(pchCmd, "$CONNECTED"))
|
||
{
|
||
zsock_send(reader, "i", self->m_bConnected);
|
||
}
|
||
else
|
||
{
|
||
//< 不正确的消息
|
||
LOGWARN("handleActorPipe(): malformed message !");
|
||
}
|
||
|
||
//< 清理,正常情况下不应有垃圾消息
|
||
if (zsock_rcvmore(reader))
|
||
{
|
||
LOGWARN("handleActorPipe(): garbage message !");
|
||
|
||
zmsg_t *more = zmsg_recv(reader);
|
||
zmsg_print(more);
|
||
zmsg_destroy(&more);
|
||
}
|
||
|
||
//< 释放
|
||
zstr_free(&pchCmd);
|
||
}
|
||
|
||
//< 任意zloop函数返回-1,则zloop退出
|
||
return bTerm ? -1 : 0;
|
||
}
|
||
|
||
int CInProcBroker::SActWorker::handleSockInCmd(zloop_t *, zsock_t *reader, void *arg)
|
||
{
|
||
SActWorker *self = (SActWorker *)arg;
|
||
|
||
assert(reader == self->m_pSockInCmd);
|
||
|
||
for (int i = 0;
|
||
(i < 10) && (zsock_events(reader) & ZMQ_POLLIN);
|
||
i++)
|
||
{
|
||
const int nRc = kmbp_recv(self->m_pKmbpMsg, reader);
|
||
if (0 != nRc)
|
||
{
|
||
//< 被系统信号打断,或者消息格式不正确,继续
|
||
LOGWARN("kmbp_recv() failed, nRc == %d", nRc);
|
||
continue;
|
||
}
|
||
|
||
//< 即通讯器名
|
||
const std::string strRoutingID((char *)zframe_data(kmbp_routing_id(self->m_pKmbpMsg)),
|
||
zframe_size(kmbp_routing_id(self->m_pKmbpMsg)));
|
||
|
||
switch (kmbp_id(self->m_pKmbpMsg))
|
||
{
|
||
case KMBP_C2P_REG:
|
||
{
|
||
self->m_pCommSet->insert(strRoutingID);
|
||
|
||
//< 回复通讯器
|
||
kmbp_set_id(self->m_pKmbpMsg, KMBP_COMMON_RETURN_TRUE);
|
||
kmbp_send(self->m_pKmbpMsg, reader, NULL, NULL);
|
||
}
|
||
break;
|
||
case KMBP_C2P_UNREG:
|
||
{
|
||
self->m_pCommSet->erase(strRoutingID);
|
||
|
||
//< 删除订阅者
|
||
{
|
||
const SubInfoVecPtr ptrVecSub =
|
||
self->m_pSubEng->delSuber(strRoutingID);
|
||
if (ptrVecSub)
|
||
{
|
||
//< 发送给本机服务
|
||
for (size_t i = 0; i < ptrVecSub->size(); i++)
|
||
{
|
||
if (zsock_events(self->m_pSockOut) & ZMQ_POLLOUT)
|
||
{
|
||
kmbp_set_id(self->m_pKmbpMsg, KMBP_P2H_SUB_DEL);
|
||
kmbp_set_sub_appid(self->m_pKmbpMsg, (*ptrVecSub)[i].m_nAppID);
|
||
kmbp_set_sub_chanid(self->m_pKmbpMsg, (*ptrVecSub)[i].m_nChannelID);
|
||
sendOut(self, self->m_pKmbpMsg);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//< 回复通讯器
|
||
kmbp_set_id(self->m_pKmbpMsg, KMBP_COMMON_RETURN_TRUE);
|
||
kmbp_send(self->m_pKmbpMsg, reader, NULL, NULL);
|
||
}
|
||
break;
|
||
case KMBP_C2P_SUB_ADD:
|
||
{
|
||
CMbSubInfoImp objSubAdd;
|
||
objSubAdd.m_nAppID = kmbp_sub_appid(self->m_pKmbpMsg);
|
||
objSubAdd.m_nChannelID = kmbp_sub_chanid(self->m_pKmbpMsg);
|
||
|
||
if (!(objSubAdd.isValid(false)))
|
||
{
|
||
//< 回复通讯器false
|
||
kmbp_set_id(self->m_pKmbpMsg, KMBP_COMMON_RETURN_FALSE);
|
||
kmbp_send(self->m_pKmbpMsg, reader, NULL, NULL);
|
||
//< 不对上发送
|
||
}
|
||
else
|
||
{
|
||
const bool bUpSend =
|
||
self->m_pSubEng->addSubtionOfSuber(strRoutingID, objSubAdd);
|
||
|
||
if (bUpSend && (zsock_events(self->m_pSockOut) & ZMQ_POLLOUT))
|
||
{
|
||
//< 发送给本机服务
|
||
kmbp_set_id(self->m_pKmbpMsg, KMBP_P2H_SUB_ADD);
|
||
sendOut(self, self->m_pKmbpMsg);
|
||
}
|
||
|
||
//< 回复通讯器
|
||
kmbp_set_id(self->m_pKmbpMsg, KMBP_COMMON_RETURN_TRUE);
|
||
kmbp_send(self->m_pKmbpMsg, reader, NULL, NULL);
|
||
}
|
||
}
|
||
break;
|
||
case KMBP_C2P_SUB_DEL:
|
||
{
|
||
CMbSubInfoImp objSubDel;
|
||
objSubDel.m_nAppID = kmbp_sub_appid(self->m_pKmbpMsg);
|
||
objSubDel.m_nChannelID = kmbp_sub_chanid(self->m_pKmbpMsg);
|
||
|
||
if (!(objSubDel.isValid(false)))
|
||
{
|
||
//< 回复通讯器false
|
||
kmbp_set_id(self->m_pKmbpMsg, KMBP_COMMON_RETURN_FALSE);
|
||
kmbp_send(self->m_pKmbpMsg, reader, NULL, NULL);
|
||
//< 不对上发送
|
||
}
|
||
else
|
||
{
|
||
//< 注意,接口库需支持通配,服务程序无需作此处理
|
||
//< 比如,现在已订阅(1,1)、(2,1)、(1,2),取消订阅(0,1),
|
||
//< 则会取消掉(1,1)和(2,1)订阅,而(1,2)保留。
|
||
|
||
bool bRet = false;
|
||
|
||
const SubInfoVecPtr ptrVecSub =
|
||
self->m_pSubEng->getSubtionOfSuber(strRoutingID);
|
||
if (ptrVecSub)
|
||
{
|
||
for (size_t i = 0; i < ptrVecSub->size(); i++)
|
||
{
|
||
const CMbSubInfoImp &Sub = (*ptrVecSub)[i];
|
||
if (objSubDel.contain(Sub))
|
||
{
|
||
bRet = true;
|
||
const bool bUpSend =
|
||
self->m_pSubEng->delSubtionOfSuber(strRoutingID, Sub);
|
||
if (bUpSend && (zsock_events(self->m_pSockOut) & ZMQ_POLLOUT))
|
||
{
|
||
//< 发送给本机服务
|
||
kmbp_set_id(self->m_pKmbpMsg, KMBP_P2H_SUB_DEL);
|
||
kmbp_set_sub_appid(self->m_pKmbpMsg, Sub.m_nAppID);
|
||
kmbp_set_sub_chanid(self->m_pKmbpMsg, Sub.m_nChannelID);
|
||
sendOut(self, self->m_pKmbpMsg);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//< 回复通讯器
|
||
if (bRet)
|
||
kmbp_set_id(self->m_pKmbpMsg, KMBP_COMMON_RETURN_TRUE);
|
||
else
|
||
kmbp_set_id(self->m_pKmbpMsg, KMBP_COMMON_RETURN_FALSE);
|
||
|
||
kmbp_send(self->m_pKmbpMsg, reader, NULL, NULL);
|
||
}
|
||
}
|
||
break;
|
||
case KMBP_C2P_SUB_ALL_REQ:
|
||
{
|
||
zlist_t *plistSub = zlist_new();
|
||
zlist_autofree(plistSub);
|
||
|
||
const SubInfoVecPtr ptrVecSub = self->m_pSubEng->getSubtionOfSuber(strRoutingID);
|
||
if (ptrVecSub)
|
||
{
|
||
for (size_t i = 0; i < ptrVecSub->size(); i++)
|
||
{
|
||
const CMbSubInfoImp &Sub = (*ptrVecSub)[i];
|
||
|
||
//< list设置了autofree,会复制内容
|
||
zlist_append(plistSub, (char *)Sub.toString().c_str());
|
||
}
|
||
}
|
||
|
||
//< 转移plistSub所有权至kmbp,kmbp内部释放
|
||
kmbp_set_sublist(self->m_pKmbpMsg, &plistSub);
|
||
|
||
//< 回复通讯器
|
||
kmbp_set_id(self->m_pKmbpMsg, KMBP_P2C_SUB_ALL);
|
||
kmbp_send(self->m_pKmbpMsg, reader, NULL, NULL);
|
||
}
|
||
break;
|
||
default:
|
||
{
|
||
LOGERROR("handleSockInCmd(): invalid kmbp_id = %d ", kmbp_id(self->m_pKmbpMsg));
|
||
}
|
||
break;
|
||
}
|
||
|
||
//< 无需清理
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
int CInProcBroker::SActWorker::handleSockInData(zloop_t *, zsock_t *reader, void *arg)
|
||
{
|
||
SActWorker *self = (SActWorker *)arg;
|
||
|
||
assert(reader == self->m_pSockInData);
|
||
|
||
for (int i = 0;
|
||
(i < 10) && (zsock_events(reader) & ZMQ_POLLIN);
|
||
i++)
|
||
{
|
||
//< self->m_pSockInData是router,第一帧是routing id
|
||
zframe_t *pFrameRoutingID = zframe_recv(reader); //< 需释放
|
||
if (!pFrameRoutingID || !zsock_rcvmore(reader))
|
||
{
|
||
LOGWARN("handleSockInData(): no routing ID , ignore !");
|
||
|
||
zframe_destroy(&pFrameRoutingID);
|
||
continue;
|
||
}
|
||
//< 即通讯器名
|
||
const std::string strRoutingID((char *)zframe_data(pFrameRoutingID),
|
||
zframe_size(pFrameRoutingID));
|
||
zframe_destroy(&pFrameRoutingID);
|
||
|
||
|
||
kmbp_cnt_t *pKmbpCnt = NULL;
|
||
//< 最后统一释放引用
|
||
if (0 != zsock_recv(reader, "p", &pKmbpCnt))
|
||
continue;
|
||
|
||
if (NULL == pKmbpCnt)
|
||
{
|
||
//< 回复通讯器NULL
|
||
|
||
zframe_t *pDstRoutingID = zframe_from(strRoutingID.c_str());
|
||
|
||
//< m_pSockInData是router,第一帧是id
|
||
//< pDstRoutingID 在 zframe_send 后已被接管,无需再释放
|
||
if (0 == zframe_send(&pDstRoutingID, self->m_pSockInData, ZFRAME_MORE))
|
||
{
|
||
zsock_send(self->m_pSockInData, "p", pKmbpCnt);
|
||
}
|
||
|
||
//< pKmbpCnt 无需释放引用
|
||
}
|
||
else //< != NULL
|
||
{
|
||
kmbp_t *pKmbp = kmbp_cnt_get(pKmbpCnt);
|
||
|
||
switch (kmbp_id(pKmbp))
|
||
{
|
||
case KMBP_C2H_DATA_PEER:
|
||
case KMBP_C2H_DATA_HOST:
|
||
case KMBP_C2H_DATA_DOMAIN:
|
||
{
|
||
if (zsock_events(self->m_pSockOut) & ZMQ_POLLOUT)
|
||
{
|
||
kmbp_set_src_host(pKmbp, self->m_chHostName);
|
||
kmbp_set_src_proc(pKmbp, self->m_chProcName);
|
||
kmbp_set_src_inst(pKmbp, self->m_chInstName);
|
||
kmbp_set_src_pid(pKmbp, self->m_nPid);
|
||
kmbp_set_src_comm(pKmbp, strRoutingID.c_str());
|
||
|
||
sendOut(self, pKmbp);
|
||
}
|
||
else
|
||
{
|
||
//< todo 是否增加额外缓存,视情况
|
||
|
||
if (g_bCommSendEnable)
|
||
{
|
||
g_bCommSendEnable = false;
|
||
}
|
||
|
||
LOGWARN("handleSockInData(): outbound queue is full , drop message !");
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
{
|
||
LOGERROR("handleSockInData(): invalid kmbp_id = %d ", kmbp_id(pKmbp));
|
||
}
|
||
break;
|
||
}
|
||
|
||
//< 释放引用
|
||
kmbp_cnt_dec(&pKmbpCnt);
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
int CInProcBroker::SActWorker::handleSockOut(zloop_t *, zsock_t *reader, void *arg)
|
||
{
|
||
SActWorker *self = (SActWorker *)arg;
|
||
|
||
assert(reader == self->m_pSockOut);
|
||
|
||
for (int i = 0;
|
||
(i < 10) && (zsock_events(reader) & ZMQ_POLLIN);
|
||
i++)
|
||
{
|
||
const int nRc = kmbp_recv(self->m_pKmbpMsg, reader);
|
||
if (0 != nRc)
|
||
{
|
||
//< 被系统信号打断,或者消息格式不正确,继续
|
||
LOGWARN("kmbp_recv() failed, nRc == %d", nRc);
|
||
continue;
|
||
}
|
||
|
||
switch (kmbp_id(self->m_pKmbpMsg))
|
||
{
|
||
case KMBP_H2P_DATA:
|
||
{
|
||
const int nDataType = kmbp_data_type(self->m_pKmbpMsg);
|
||
|
||
if (nDataType == MB_MT_PING_PROC
|
||
|| nDataType == MB_MT_PING_PROC_IN_HOST)
|
||
{
|
||
//< 响应Ping
|
||
|
||
kmbp_t *pKmbpSend = self->m_pKmbpMsg;
|
||
|
||
//< 设置回复消息内容
|
||
{
|
||
kmbp_set_id(pKmbpSend, KMBP_C2H_DATA_PEER);
|
||
|
||
kmbp_set_timestamp(pKmbpSend, zclock_mono());
|
||
|
||
kmbp_set_relaystat(pKmbpSend, MB_RS_DEFAULT);
|
||
|
||
kmbp_set_dst_comm(pKmbpSend, kmbp_src_comm(pKmbpSend));
|
||
kmbp_set_dst_proc(pKmbpSend, kmbp_src_proc(pKmbpSend));
|
||
kmbp_set_dst_inst(pKmbpSend, kmbp_src_inst(pKmbpSend));
|
||
kmbp_set_dst_pid(pKmbpSend, kmbp_src_pid(pKmbpSend));
|
||
kmbp_set_dst_host(pKmbpSend, kmbp_src_host(pKmbpSend));
|
||
|
||
kmbp_set_src_host(pKmbpSend, self->m_chHostName);
|
||
kmbp_set_src_proc(pKmbpSend, self->m_chProcName);
|
||
kmbp_set_src_inst(pKmbpSend, self->m_chInstName);
|
||
kmbp_set_src_pid(pKmbpSend, self->m_nPid);
|
||
kmbp_set_src_comm(pKmbpSend, "");
|
||
|
||
kmbp_set_data_type(pKmbpSend, MB_MT_PING_PROC_REP);
|
||
}
|
||
|
||
//< 发出
|
||
sendOut(self, pKmbpSend);
|
||
}
|
||
else
|
||
{
|
||
//< 点对点消息(C2H_DATA_PEER),Dst_Comm不为空,直接投送给通讯器。
|
||
//< 其他类型消息,Dst_Comm为空,进程内再进行主题、订阅匹配。
|
||
StrVecPtr ptrVecComm;
|
||
{
|
||
const char *pchComm = kmbp_dst_comm(self->m_pKmbpMsg);
|
||
if (strlen(pchComm) > 0)
|
||
{
|
||
ptrVecComm.reset(new StrVec);
|
||
ptrVecComm->push_back(std::string(pchComm));
|
||
}
|
||
else
|
||
{
|
||
const CMbSubInfoImp objSub(kmbp_sub_appid(self->m_pKmbpMsg),
|
||
kmbp_sub_chanid(self->m_pKmbpMsg));
|
||
ptrVecComm = self->m_pSubEng->lookupSuberOfSubject(objSub);
|
||
}
|
||
}
|
||
|
||
if (ptrVecComm)
|
||
{
|
||
if (nDataType == MB_MT_PING_SUBER_IN_DOMAIN
|
||
|| nDataType == MB_MT_PING_SUBER_IN_HOST
|
||
|| nDataType == MB_MT_PING_SUBER_IN_PROC)
|
||
{
|
||
//< 响应 ping
|
||
|
||
kmbp_t *pKmbpSend = self->m_pKmbpMsg;
|
||
|
||
//< 设置回复消息内容
|
||
{
|
||
kmbp_set_id(pKmbpSend, KMBP_C2H_DATA_PEER);
|
||
|
||
kmbp_set_timestamp(pKmbpSend, zclock_mono());
|
||
|
||
kmbp_set_relaystat(pKmbpSend, MB_RS_DEFAULT);
|
||
|
||
kmbp_set_dst_comm(pKmbpSend, kmbp_src_comm(pKmbpSend));
|
||
kmbp_set_dst_proc(pKmbpSend, kmbp_src_proc(pKmbpSend));
|
||
kmbp_set_dst_inst(pKmbpSend, kmbp_src_inst(pKmbpSend));
|
||
kmbp_set_dst_pid(pKmbpSend, kmbp_src_pid(pKmbpSend));
|
||
kmbp_set_dst_host(pKmbpSend, kmbp_src_host(pKmbpSend));
|
||
|
||
kmbp_set_src_host(pKmbpSend, self->m_chHostName);
|
||
kmbp_set_src_proc(pKmbpSend, self->m_chProcName);
|
||
kmbp_set_src_inst(pKmbpSend, self->m_chInstName);
|
||
kmbp_set_src_pid(pKmbpSend, self->m_nPid);
|
||
//kmbp_set_src_comm(pKmbpSend, "");
|
||
|
||
kmbp_set_data_type(pKmbpSend, MB_MT_PING_SUBER_REP);
|
||
}
|
||
|
||
for (size_t i = 0; i < ptrVecComm->size(); i++)
|
||
{
|
||
const std::string *pStrDstComm = &((*ptrVecComm)[i]);
|
||
|
||
//< 跳过已注销的通讯器
|
||
BOOST_AUTO(itComm, self->m_pCommSet->find(*pStrDstComm));
|
||
if (self->m_pCommSet->end() == itComm)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
kmbp_set_src_comm(pKmbpSend, pStrDstComm->c_str());
|
||
|
||
//< 发出
|
||
sendOut(self, pKmbpSend);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
kmbp_set_id(self->m_pKmbpMsg, KMBP_P2C_DATA);
|
||
|
||
//< 解压消息数据
|
||
decompressData(self->m_pKmbpMsg);
|
||
|
||
kmbp_cnt_t *pKmbpCnt = kmbp_cnt_new();
|
||
kmbp_cnt_swap(pKmbpCnt, &(self->m_pKmbpMsg));
|
||
|
||
for (size_t i = 0; i < ptrVecComm->size(); i++)
|
||
{
|
||
const std::string *pStrDstComm = &((*ptrVecComm)[i]);
|
||
|
||
//< 跳过已注销的通讯器
|
||
BOOST_AUTO(itComm, self->m_pCommSet->find(*pStrDstComm));
|
||
if (self->m_pCommSet->end() == itComm)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
zframe_t *pFrameRoutingID = zframe_from(pStrDstComm->c_str());
|
||
|
||
//< m_pSockInData是router,第一帧是id
|
||
//< pFrameRoutingID在zframe_send后已被接管,无需再释放
|
||
if (0 == zframe_send(&pFrameRoutingID, self->m_pSockInData, ZFRAME_MORE))
|
||
{
|
||
//< 先加对端引用,若失败再减
|
||
//< 防止在增加引用计数前,对侧收到并释放
|
||
kmbp_cnt_inc(pKmbpCnt);
|
||
if (0 != zsock_send(self->m_pSockInData, "p", pKmbpCnt))
|
||
{
|
||
//< 失败,释放对端引用
|
||
kmbp_cnt_dec(&pKmbpCnt);
|
||
|
||
LOGWARN("handleSockOut(): send to m_pSockInData failed , unexpected !");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
LOGWARN("handleSockOut(): send to m_pSockInData failed , unexpected !");
|
||
}
|
||
}
|
||
|
||
//< 释放本端引用
|
||
kmbp_cnt_dec(&pKmbpCnt);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case KMBP_H2P_SUB_ALL_REQ:
|
||
{
|
||
zlist_t *plistSub = zlist_new();
|
||
zlist_autofree(plistSub);
|
||
|
||
const SubInfoVecPtr ptrVecSub = self->m_pSubEng->getSubtionOfAll();
|
||
if (ptrVecSub)
|
||
{
|
||
for (size_t i = 0; i < ptrVecSub->size(); i++)
|
||
{
|
||
const CMbSubInfoImp &Sub = (*ptrVecSub)[i];
|
||
//< zlist设置了autofree,会复制数据
|
||
zlist_append(plistSub, (char *)(Sub.toString().c_str()));
|
||
}
|
||
}
|
||
|
||
//< 转移zlist所有权至kmbp,kmbp内部释放
|
||
kmbp_set_sublist(self->m_pKmbpMsg, &plistSub);
|
||
|
||
kmbp_set_id(self->m_pKmbpMsg, KMBP_P2H_SUB_ALL);
|
||
sendOut(self, self->m_pKmbpMsg);
|
||
}
|
||
break;
|
||
default:
|
||
{
|
||
LOGERROR("handleSockOut(): invalid kmbp_id = %d ", kmbp_id(self->m_pKmbpMsg));
|
||
}
|
||
break;
|
||
}
|
||
|
||
//< 无需清理
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
int CInProcBroker::SActWorker::handleCycTaskTimer(zloop_t * /*loop*/, int /*timer_id*/, void *arg)
|
||
{
|
||
SActWorker *self = (SActWorker *)arg;
|
||
|
||
//< 判断可以不阻塞地发出
|
||
if (zsock_events(self->m_pSockOut) & ZMQ_POLLOUT)
|
||
{
|
||
if (!g_bCommSendEnable)
|
||
{
|
||
g_bCommSendEnable = true;
|
||
}
|
||
|
||
if (self->m_bConnected)
|
||
{
|
||
//< 发送心跳
|
||
kmbp_set_id(self->m_pKmbpMsg, KMBP_P2H_HEARTBEAT);
|
||
sendOut(self, self->m_pKmbpMsg);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (g_bCommSendEnable)
|
||
{
|
||
g_bCommSendEnable = false;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
int CInProcBroker::SActWorker::handleSockOutMon(zloop_t *, zsock_t *reader, void *arg)
|
||
{
|
||
SActWorker *self = (SActWorker *)arg;
|
||
|
||
assert(reader == self->m_pSockOutMon);
|
||
|
||
for (int i = 0;
|
||
(i < 10) && (zsock_events(reader) & ZMQ_POLLIN);
|
||
i++)
|
||
{
|
||
//< ZMQ v4版本的格式,老版本的格式不一样
|
||
//< 第一帧
|
||
int nEvent = 0, nValue = 0;
|
||
{
|
||
zframe_t *pFrame = zframe_recv(reader); //< 需释放
|
||
if (NULL == pFrame)
|
||
{
|
||
//< 被系统信号打断
|
||
continue;
|
||
}
|
||
if (!zsock_rcvmore(reader))
|
||
{
|
||
//< 没有后续帧,证明格式错误
|
||
zframe_destroy(&pFrame); //< 释放
|
||
|
||
LOGWARN("handleSockOutMon(): malformed zmonitor msg !");
|
||
|
||
continue;
|
||
}
|
||
nEvent = *(uint16_t *)(zframe_data(pFrame));
|
||
nValue = *(uint32_t *)(zframe_data(pFrame) + 2);
|
||
zframe_destroy(&pFrame); //< 释放
|
||
}
|
||
|
||
//< 第二帧
|
||
std::string strAddr;
|
||
{
|
||
char *pchAddress = zstr_recv(reader); //< 需释放
|
||
if (NULL == pchAddress)
|
||
{
|
||
//< 被系统信号打断,再试一次
|
||
pchAddress = zstr_recv(reader);
|
||
if (NULL == pchAddress)
|
||
{
|
||
LOGWARN("handleSockOutMon(): recv address failed !");
|
||
}
|
||
}
|
||
|
||
if (NULL == pchAddress)
|
||
strAddr = "UNKNOWN";
|
||
else
|
||
strAddr = pchAddress;
|
||
|
||
//< 释放,传入NULL是安全的
|
||
zstr_free(&pchAddress);
|
||
}
|
||
|
||
const char *pchName;
|
||
switch (nEvent)
|
||
{
|
||
case ZMQ_EVENT_ACCEPTED:
|
||
pchName = "ACCEPTED";
|
||
break;
|
||
case ZMQ_EVENT_ACCEPT_FAILED:
|
||
pchName = "ACCEPT_FAILED";
|
||
break;
|
||
case ZMQ_EVENT_BIND_FAILED:
|
||
pchName = "BIND_FAILED";
|
||
break;
|
||
case ZMQ_EVENT_CLOSED:
|
||
pchName = "CLOSED";
|
||
break;
|
||
case ZMQ_EVENT_CLOSE_FAILED:
|
||
pchName = "CLOSE_FAILED";
|
||
break;
|
||
case ZMQ_EVENT_DISCONNECTED:
|
||
{
|
||
pchName = "DISCONNECTED";
|
||
self->m_bConnected = false;
|
||
}
|
||
break;
|
||
case ZMQ_EVENT_CONNECTED:
|
||
{
|
||
pchName = "CONNECTED";
|
||
self->m_bConnected = true;
|
||
}
|
||
break;
|
||
case ZMQ_EVENT_CONNECT_DELAYED:
|
||
pchName = "CONNECT_DELAYED";
|
||
break;
|
||
case ZMQ_EVENT_CONNECT_RETRIED:
|
||
pchName = "CONNECT_RETRIED";
|
||
break;
|
||
case ZMQ_EVENT_LISTENING:
|
||
pchName = "LISTENING";
|
||
break;
|
||
case ZMQ_EVENT_MONITOR_STOPPED:
|
||
{
|
||
pchName = "MONITOR_STOPPED";
|
||
LOGERROR("ZMQ_EVENT_MONITOR_STOPPED , unexpected while running !");
|
||
}
|
||
break;
|
||
|
||
default:
|
||
pchName = "UNKNOWN";
|
||
break;
|
||
}
|
||
|
||
LOGINFO("Message bus api connection with local service : \n Event = %s ; Value = %d ; Addr = %s ;",
|
||
pchName, nValue, strAddr.c_str());
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
/*========================= CInProcBroker =========================*/
|
||
|
||
CInProcBroker::CInProcBroker()
|
||
{
|
||
//< 取消CZMQ对系统信号的截取
|
||
zsys_handler_set(NULL);
|
||
|
||
m_pActor = NULL;
|
||
}
|
||
|
||
CInProcBroker::~CInProcBroker()
|
||
{
|
||
//< zactor_destroy()向zactor线程发送"$TERM"消息,并等待返回消息
|
||
//< 线程内收到该消息后释放相关资源,见handleActorPipe()函数
|
||
zactor_destroy(&m_pActor);
|
||
|
||
//< 明确地提前调用zsys_shutdown(),而非程序退出时自动调用(顺序不可控)
|
||
//< 防止Windows系统下报错:Assertion failed: Successful WSASTARTUP not yet performed
|
||
zsys_shutdown();
|
||
}
|
||
|
||
bool CInProcBroker::start(const char *pchProcName, const char *pchInstName,
|
||
bool bAddPid)
|
||
{
|
||
if (NULL != m_pActor)
|
||
return false;
|
||
|
||
SActWorkerInitArg stArgs;
|
||
stArgs.m_pchProcName = pchProcName;
|
||
stArgs.m_pchInstName = pchInstName;
|
||
stArgs.m_bAddPid = bAddPid;
|
||
|
||
zactor_t *pActor = zactor_new(SActWorker::actorMain, &stArgs);
|
||
if (NULL == pActor)
|
||
return false;
|
||
|
||
int nStarted = 0;
|
||
zsock_recv(pActor, "i", &nStarted);
|
||
if (nStarted)
|
||
{
|
||
m_pActor = pActor;
|
||
return true;
|
||
}
|
||
|
||
zactor_destroy(&pActor);
|
||
return false;
|
||
}
|
||
|
||
bool CInProcBroker::isConnected()
|
||
{
|
||
if (NULL == m_pActor)
|
||
return false;
|
||
|
||
int nConnected;
|
||
zsock_send(m_pActor, "s", "$CONNECTED");
|
||
|
||
//< 接收,阻塞直到有回复
|
||
zsock_recv(m_pActor, "i", &nConnected);
|
||
|
||
return nConnected == 1;
|
||
}
|
||
|
||
} //< namespace iot_net
|
||
|