总结较好的文档:http://www.ityran.com/archives/240
/*
若1秒内对同一个用户产生大量的推送请求,会造成该用户接收正常速度的消息时前总是收到之前已经推送过的消息,这所谓重复消息。 经过测试发现,即便provider产生大量推送请求,apns推送给iPhone的时间间隔大约为3s。那么应该在provider端设计一种算法,使得 对同一个用户大量并发的请求以3秒间隔地推送。实践结果,果然。
*/
#pragma pack(1)
struct STRU_PUSHDATA
{
public:
void setFieldCommand(uint8 auCommand)
{
muCommand = auCommand;
}
void setFieldIdentifier(uint32 auIdentifier)
{
muIdentifier = auIdentifier;
}
void setFieldExpiry(uint32 auExpiry)
{
muExpiry = htonl(auExpiry);
}
void setFieldTokenLen(uint16 auTokenLen)
{
muTokenLen = htons(auTokenLen);
}
void setFieldToken(
const uint8* apToken)
{
memcpy(mszToken,apToken,32);
}
void setFieldPayloadLen(uint16 auPayloadLen)
{
muPayloadLen = htons(auPayloadLen);
}
void setFieldPayLoad(
const char* apszPayload,uint16 auPayloadLen)
{
memcpy(mszPayload,apszPayload,auPayloadLen);
}
inline
const uint8* getPushDataAddr()
const {
return (uint8*)&muCommand;
}
inline uint16 getPushDataLen()
{
return (1+4+4+2+32+2+getPayloadLen());
}
inline uint16 getPayloadLen()
{
return ntohs(muPayloadLen);
}
std::
string getPayloadString()
{
int nLen = getPayloadLen();
if (nLen>=256)
{
return std::
string("");
}
mszPayload[nLen]='\0';
return std::
string(mszPayload);
}
inline
void setFieldFromId(
const uint64& auFromId)
{
muFromId = auFromId;
}
inline
void setFieldToId(
const uint64& auToId)
{
muToId = auToId;
}
inline
const uint64& getFieldFromId()
const {
return muFromId;
}
inline
const uint64& getFieldToId()
const {
return muToId;
}
STRU_PUSHDATA()
{
init();
}
void init()
{
memset(
this,0,
sizeof(*
this));
}
uint8 muCommand;
uint32 muIdentifier;
uint32 muExpiry;
uint16 muTokenLen;
uint8 mszToken[32];
uint16 muPayloadLen;
char mszPayload[256+1];
uint16 iPayloaLlen;
uint64 muFromId;
uint64 muToId;
STRU_PUSHDATA* next;
//*指向下一个STRU_PUSHDATA
};
#pragma pack(0)
// 类名:CApnsAdapter
// 功能:与apns交互的适配器,适配器时一个包含各种推送策略的推送发射装置
// 设计者:zhangtao 20140419
typedef
void (*PFCALLBACK_EVENT_ON_TRAVERSAL)(HANDLE ahCallBack,STRU_PUSHDATA* apData);
typedef
void (*PFCALLBACK_EVENT_ON_CLEARCACHE)(HANDLE ahCallBack,STRU_PUSHDATA* apData);
class CApnsAdapter
{
public:
struct HEAD_NODE
{
uint64 muToId;
uint32 muLastPushTime;
STRU_PUSHDATA* mpHead;
STRU_PUSHDATA* mpTail;
uint32 muCount;
HEAD_NODE():muToId(0),muLastPushTime(0),mpHead(NULL),mpTail(NULL),muCount(0)
{
//*构造
}
HEAD_NODE(uint64 auId,uint32 auTime):muToId(auId),muLastPushTime(auTime),mpHead(NULL),mpTail(NULL),muCount(0)
{
//*构造
}
bool operator==(
const HEAD_NODE& rhs)
const {
return (muToId == rhs.muToId);
}
void push_back(STRU_PUSHDATA* mpData)
{
if(NULL == mpHead)
{
mpHead = mpData;
}
else {
mpTail->next = mpData;
}
mpData->next = NULL;
mpTail = mpData;
muCount++;
}
STRU_PUSHDATA* pop_front()
{
if (NULL == mpHead || NULL ==mpTail)
{
return NULL;
}
STRU_PUSHDATA* lpData = mpHead;
mpHead = mpHead->next;
muCount--;
return lpData;
}
STRU_PUSHDATA* get_front()
{
if (NULL == mpHead || NULL ==mpTail)
{
return NULL;
}
return mpHead;
}
bool is_empty()
{
return ( NULL == mpHead) ;
}
uint16 get_count()
{
return muCount;
}
void set_lastpushtime(
const uint32& auCurTime)
{
muLastPushTime = auCurTime;
}
bool is_canpush(
const uint32& auCurTime)
{
return (auCurTime >= muLastPushTime+3);
//3是实践出来的值
}
};
CApnsAdapter():mhcbContext(NULL),mpcbEventOnTraversal(NULL),mpcbEventOnClearCache(NULL)
{
}
~CApnsAdapter()
{
clear_all_cache();
}
void setCallbackEvent(HANDLE ahcbContext,PFCALLBACK_EVENT_ON_TRAVERSAL apcbEventOnTraversal,PFCALLBACK_EVENT_ON_CLEARCACHE apcbEventOnClearCache)
{
mhcbContext = ahcbContext;
mpcbEventOnTraversal = apcbEventOnTraversal;
mpcbEventOnClearCache = apcbEventOnClearCache;
}
bool is_empty()
{
return ( 0 == moNodeList.size());
}
uint16 size()
{
return moNodeList.size();
}
//*先缓冲待推送的数据请求,然后又策略地推送
void add_data_to_cache( STRU_PUSHDATA* mpData)
{
HEAD_NODE node(mpData->getFieldToId(),0);
std::list<HEAD_NODE>::iterator it = std::find(moNodeList.begin(),moNodeList.end(),node);
if (it != moNodeList.end())
{
it->push_back(mpData);
}
else {
node.push_back(mpData);
moNodeList.push_back(node);
}
}
void active_push_on_traversal()
{
uint32 uNowTime = (uint32)time(NULL);
std::list<HEAD_NODE>::iterator it = moNodeList.begin();
for ( ; it != moNodeList.end() ;)
{
if ( it->is_canpush( uNowTime ))
{
if ( it->is_empty() )
{
moNodeList.erase( it++ );
continue;
}
else {
STRU_PUSHDATA * lpData = it->pop_front()
if ( NULL != mpcbEventOnTraversal)
{
mpcbEventOnTraversal(mhcbContext,lpData);
}
it->set_lastpushtime( uNowTime );
}
}
else {
}
it++;
}
}
void clear_all_cache()
{
std::list<HEAD_NODE>::iterator it = moNodeList.begin();
for ( ; it != moNodeList.end() ;)
{
if ( it->is_empty() )
{
moNodeList.erase( it++ );
continue;
}
else {
STRU_PUSHDATA* lpPushData = NULL;
while( NULL != (lpPushData = it->pop_front()) )
{
if ( NULL != mpcbEventOnClearCache)
{
mpcbEventOnClearCache(mhcbContext,lpPushData);
}
}
it++;
}
}
moNodeList.clear();
}
void print_each_node();
private:
std::list<HEAD_NODE> moNodeList;
HANDLE mhcbContext;
PFCALLBACK_EVENT_ON_TRAVERSAL mpcbEventOnTraversal;
PFCALLBACK_EVENT_ON_CLEARCACHE mpcbEventOnClearCache;
};