视频监控安防平台-GB28181-系统目录查询TCP协议和系统录像文件检索TCP协议
国标28181-2016检测的时候标准规定了平台必须支持系统目录查询和系统录像文件检索回应必须支持TCP,主要是由于这两个的资源数量比较多,采用TCP比较更安全可靠,tcp发送流程简单讲就是收到目录查询或则录像文件检索的时候,建立一个临时的tcpclient去连接平台地址,将目录回应的信息和录像文件检索的信息全部发送到上级(这里注意每次发送的大小最好不要超过10M),收到上级回复的200OK再发生下一组资源列表。下面简单讲解下两个流程,两个流程都采用的是有应答设备控制流程:
命令流程描述如下:
a ) 1 : 源设备向 S I P 服务器发送设备控制命令, 设备控制命令采用 M e s s a g e 方法携带;
b ) 2 : S I P 服务器收到命令后返回 2 0 0OK ;
c ) 3 : S I P 服务器向目标设备发送设备控制命令, 设备控制命令采用 M e s s a g e 方法携带;
d ) 4 : 目标设备收到命令后返回 2 0 0OK ;
e ) 5 : 目标设备向 S I P 服务器发送设备控制响应命令, 设备控制响应命令采用 M e s s a g e 方法携带;
f ) 6 : S I P 服务器收到命令后返回 2 0 0OK ;
g ) 7 : S I P 服务器向源设备转发设备控制响应命令, 设备控制响应命令采用 M e s s a g e 方法携带;
h ) 8 : 源设备收到命令后返回 2 0 0OK 。
消息示范见 J .
粘贴一下系统目录查询检测的图片:
录像文件检索截图:
下面粘贴一下系统目录查询和系统录像文件检索tcp管理的发送代码逻辑,支持多个tcp连接:
// 版权说明, 2010-2020,
// 文件名 : SipTcpConnectMgr.h
// 作 者 :
// 版 本 : 1.0
// 日 期 : 2016-07-08
// 功能描述: 和上级平台建立tcp短连接的管理 接收数据和发送数据处理
// 其他说明:
//
// 修改历史:
// 日期(YYYY-MM-DD) 版本 修改人 修改内容
// 2016-07-08 1.0 宋小文 初始创建
#ifndef __SIP_TCP_CONNECT_MGR_H__
#define __SIP_TCP_CONNECT_MGR_H__
using namespace std;
#include "StrHash.h"
#include "TypeDef.h"
#include "publicid.h"
#include "structs.h"
#include "Log.h"
#include "Module.h"
#include "SysIf.h"
#include "MsgCenter.h"
#include "SPushCatalog.h"
#include "jthread.h"
#include <sys/socket.h>
#include "osip2/osip.h"
#include "osipparser2/osip_list.h"
#include "eXosip2/eXosip.h"
#include "osipparser2/osip_uri.h"
//#include "eXosip2.h"
//#include "ABase.h"
using namespace jthread;
/* ASC-II char mapped table */
#define TCP_CHAR_LIST_NUMBER 62
static const char TCP_CHAR_LIST_MAP[TCP_CHAR_LIST_NUMBER] =
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9'
};
#define TCP_MAX_CONNECT_TIME 60 //建立TCP最大的时间,超过将删除tcp连接 从最后一次发送tcp包时间算起 s
typedef enum
{
TC_NOTIFY_CATALOG, //tcp 发送notify 目录资源
TC_MESSAGE_CATALOG, //tcp发送message目录资源
TC_MESSAGE_RECOED //tcp发送message录像查询
}TcpSendType_E;
class CSipTcpConnect: public JThread
{
public:
CSipTcpConnect(void);
~CSipTcpConnect(void);
public:
bool Init(const char *pEpAor, const char* pDsIp, int nPort);
void Unit(void);
void SetSubNotifyInfo(osip_call_id_t *pCall_id, osip_from_t *pFrom, osip_to_t *pTo, TSendNotifyInfo NotifyInfo);
int SendSipPacket(void *pData, TcpSendType_E etype);
bool IsTimeOut();
void SetTcpPushPolicy(UpperPolicy_T PushPolicy)
{
TcpPushPolicy = PushPolicy;
}
private:
int Connect(const char* pDsIp, int nPort);
void SipTcpStickyPacket(const char *pData, int len);
int RecvFullSipPacket(char *pData, int len);
int Recv(int h, char* buff, int len, int timeout);
void RecvAndParse(void);
int SendMessage(string strMessage, TcpSendType_E etype = TC_MESSAGE_CATALOG);
int SendSubNotify(const char* pXmlStr, TcpSendType_E etype = TC_NOTIFY_CATALOG);
int SendTcpData(osip_message_t* pSipMsg, TcpSendType_E etype, bool bCloneCallid = true);
int CloneCallId(const osip_call_id_t* pCallId, TcpSendType_E etype = TC_MESSAGE_CATALOG);
bool IsTheSameCallId(osip_call_id_t *pCallId, TcpSendType_E etype = TC_MESSAGE_CATALOG);
unsigned int TcpGetCSeq(void);
unsigned int TcpGenerateRandom(UINT32 i1, UINT32 i2);
char* TcpGenerateRandomCallID(char* pStr);
char* TcpGenerateRandomBranchParam(char* pStr);
char* TcpGenerateRandomTag(char* pStr);
int TcpBuildSipNotify(osip_message_t*& pDest, const char Method[], const osip_from_t* pFrom, const osip_to_t* pTo, const osip_call_id_t* pCallId, const osip_list_t* pRoute, const osip_contact_t* pContact);
int TcpBuildSipRequest(osip_message_t*& pDest, const char Method[], const char *pFrom, const char *pTo, const char Contact[], const char *pRoute, char* Proxy = NULL);
private:
//Jstream Entry Point
void* Thread(void);
void ThreadQuit(void);
public:
char m_DevPubID[PUBID_TOTAL_LEN+1]; //上级平台或则客户端的 地址编码 唯一标识符
//TraverseAddr_T TvsAddr;
private:
int m_ConnectTime; //tcp 连接的时间,每次发送数据 更新相应的时间
TcpSendType_E m_eTcpSendType; //tcp发送数据的类型
bool ExitFlag;
int m_SocketFd; //建立TCP的句柄
//char From[SIP_AOR_MAX_SIZE+1]; //SIP消息的from信息
//char To[SIP_AOR_MAX_SIZE+1]; //SIP消息的to信息
//char Route[SIP_AOR_MAX_SIZE+1]; //SIP消息的Route信息
char *m_RecvBuf; //TCP接收得buffer (单个包)
//TCP粘包后的数据和长度
char *m_TcpRecvData; //TCP接收一个完整sip包的数据
int m_nTcpRecvLen; //TCP接收一个完整sip包的长度
CPushCatalog MsgPushCatalog; //message推送资源的类,编译接收200OK后再发送下一条资源
osip_call_id_t *m_pCatalogCallId; //keepalive callid
bool m_bSubNotify; //判断是否为订阅notify
CPushCatalog NotifyPushCatalog;
osip_call_id_t *m_pNotifyCallId; //keepalive callid
osip_from_t *m_pSubNotifyFrom;
osip_to_t *m_pSubNotifyTo;
TSendNotifyInfo m_SubNotifyInfo;
//连接及登录信息
char m_cDSIP[16]; //服务器的ip地址
int m_nDSPort; //服务器的port
//资源推送的策略
UpperPolicy_T TcpPushPolicy;
};
class CSipTcpConnectMgr:public CMyThread
{
public:
CSipTcpConnectMgr(void);
~CSipTcpConnectMgr(void);
public:
//Allocate and delete class instance
static CSipTcpConnectMgr* GetInstance(void)
{
static CSipTcpConnectMgr TcpConnectMgr;
return &TcpConnectMgr;
}
int SendTcpPacket(const char EpAor[], const char* pDsIp, int nPort, void *pData, UpperPolicy_T PushPolicy, TcpSendType_E etype);
CSipTcpConnect* OpenATcpConnect(const char EpAor[], const char* pDsIp, int nPort, UpperPolicy_T PushPolicy);
private:
//Main Worker Thread function
int ThreadProc(void);
private:
CSipTcpConnect* FindATcpConnect(const char EpAor[]);
void RemoveATcpConnect(const char EpAor[]);
int PollTcpConnect(void);
private:
bool m_bStart;
static CStrHash<CSipTcpConnect> TcpConnectHashList;
static CCritSec CritSec_TcpConnectMgr;
};
#endif //#if !defined(__DEVICECONTROL_PRIORITY_MGR_H__)