共享内存队列类:(结构体Header,结构体Record,结构体Attr)
共享内存队列
class ShmQueue {
public:
/**
* 队列头
*/
struct Header {
volatile unsigned int head;
volatile unsigned int tail;
unsigned int size;
time_t createTime;
long long in;
long long out;
};
/**
* 记录头
*/
struct Record {
enum {
FRM_FIRST = 0x1, /**< 首个请求片断 */
FRM_LAST = 0x2, /**< 最后一个请求片断 */
FRM_ALL = FRM_FIRST | FRM_LAST, /**< 完整数据包 */
FRM_ERR = 0x4, /**< 错误包 */
FRM_NULL = 0x8, /**< 空包 */
HAS_ATTR = 0x10, /**< 带有 attr */
END_OF_QUEUE = 0x20, /**< 队列结束 */
REQ_PENDING = 0x40, /**< 正在处理中 */
REQ_TRANSIT = 0x80, /**< 是否中转产生的请求 */
};
enum Mask {
NEWSYNC_MASK = 0x1,
VOIPSYNC_MASK = 0x2,
};
Record() {
memset(this, 0, sizeof(Record));
}
enum {
};
unsigned int uid;
unsigned int clientId;
unsigned int cmd;
unsigned int seq;
unsigned int flags;
unsigned int len;
long long time;
unsigned int mask;
};
/**
* LogicAttr, 只能增加字段,不能删除字段
*/
struct LogicAttr {
unsigned int logicLen; // 整个LogicAttr的长度
long long reqTime;
unsigned char deviceId[16];
unsigned short clientType;
unsigned int state;
unsigned int ver;
//unsigned int notifyMask;
unsigned int last_check_act_time;
char sessionKey[32];
//unsigned short keyLen;
//char keyBuf[128];
unsigned int terminal_type; //for Happy-City web client
char reserved[16];
};
/**
* 基本属性
*/
struct BasicAttr {
long long connTime;
long long activeTime;
unsigned int clientIp;
unsigned int serverIp;
unsigned short clientPort;
unsigned short serverPort;
unsigned int reqCount;
unsigned int respCount;
unsigned int oobCount;
unsigned int reqBytes;
unsigned int respBytes;
unsigned int oobBytes;
unsigned short pendingReqCount;
unsigned short pendingRespCount;
unsigned short pendingOobCount;
};
/**
* 属性
*/
struct Attr {
BasicAttr basic;
LogicAttr logic;
};
/**
* 构造函数
*/
ShmQueue() : _header(0), _base(0), _fifo(-1) {}
/**
* 析构函数
*/
~ShmQueue() {
close();
}
/**
* 获取header
*/
Header* header() const {
return _header;
}
分配空间函数:
在共享内存内循环使用
unsigned int alloc(unsigned int n, unsigned int& begin) const {
begin = _header->tail;//为了再次分配是从上次数据尾部开始
if (_header->tail < _header->head) { // tail -> head,此时尾部在前
if (_header->tail + n < _header->head) {//如果尾部到头部空间大于n,可以分配
return _header->tail + n;
}
return _header->tail; // 没空间
} else if (_header->tail + n <= _header->size) { // head -> tail,头部在前,_header->size是分配空间减去Header
return _header->tail + n;
} else {//头部在前,尾部不够空间分配
// 舍弃最后一段, 从头开始分配,再判断开始位置到header距离
if (n < _header->head) {
// 设置队列结束标识
if (_header->tail + sizeof(Record) <= _header->size) {
Record record;
record.flags = Record::END_OF_QUEUE;
memcpy(_base + _header->tail, &record, sizeof(Record));
}
begin = 0;
return n;
}
return _header->tail; // 没空间
}
}
添加数据函数
/**
* 写入数据到队列
*/
size_t add(Record& record, Attr* attr, mm::ByteBuffer* data) {
// 计算空间
if (!data) {
record.len = 0;
}
unsigned int len = record.len + sizeof(Record);//为什么需要在前面加上record.len,其代表的是什么,应该是在接收到
if (attr) {
/*if (attr->logic.logicLen == 0) {
attr->logic.logicLen = 4;
}*/
len += sizeof( Attr );
//len += sizeof( Attr ) - sizeof( LogicAttr ) + attr->logic.logicLen ;
record.flags |= Record::HAS_ATTR;
} else {
record.flags &= ~Record::HAS_ATTR;
}
// 分配空间
unsigned int begin = 0;
unsigned int tail = alloc(len, begin);//??
// 写入数据
if (tail != _header->tail) {
// record
memcpy(_base + begin, &record, sizeof(Record));
begin += sizeof(Record);
// attr
if (attr) {
memcpy(_base + begin, attr, sizeof(Attr));
//begin += sizeof(Attr) - sizeof(LogicAttr) + attr->logic.logicLen;
begin += sizeof(Attr);
}
// data
if (data) {
data->read(_base + begin, record.len);
}
Comm::LogDebug("client %u uin %u write %u bytes to queue %d [ %u %u %u ]",
record.clientId, record.uid, record.len, _shmId, _header->head,
_header->tail, _header->size);
/* if (attr)
{
Comm::LogDebug("DEBUG_G: logic:%d", attr->logic.logicLen);
}
if (data)
{
Comm::LogDebug("DEBUG_G: to queue pos:%d len:%d:%s ", begin, record.len, data->base());
}*/
_header->tail = tail;
_header->in++;
return len;
} else {
Comm::LogDebug("client %u uin %u ERR: failed to write %u bytes to queue %d [ %u %u %u ]",
record.clientId, record.uid, record.len, _shmId, _header->head,
_header->tail, _header->size);
return 0;
}
}
取数据
/**
* 从队列获取数据
*/
size_t get(Record& record, Attr& attr, mm::ByteBuffer& data) {
if (_header->head != _header->tail) {
// 判断是否移动到开头
if (_header->head + sizeof(Record) > _header->size) {
_header->head = 0;
}//这里为什么要这样移动
// record
memcpy(&record, _base + _header->head, sizeof(Record));
if (record.clientId == 0 && record.uid == 0 && record.cmd == 0
&& record.flags == Record::END_OF_QUEUE) {
// 切换到开头, 再读一次
_header->head = 0;
memcpy(&record, _base, sizeof(Record));
}
// attr
unsigned int len = sizeof(Record);
if (record.flags & Record::HAS_ATTR) {
memcpy(&attr, _base + _header->head + len, sizeof(Attr));
len += sizeof(Attr);
// len += sizeof( Attr ) - sizeof( LogicAttr ) + attr.logic.logicLen;
/*if (attr.logic.logicLen == 4) {
attr.logic.logicLen = 0;
}*/
}
// data
data.write(_base + _header->head + len, record.len);
len += record.len;
Comm::LogDebug("client %u uin %u read %u bytes from queue %d [ %u %u %u ]",
record.clientId, record.uid, record.len, _shmId,
_header->head, _header->tail, _header->size);
// Comm::LogDebug("DEBUG_G:getqueue pos:%d logic:%d %d %d", _header->head + len - record.len, attr.logic.logicLen, data.remaining(), data.base());
_header->head += len;
_header->out++;
return len;
} else {
record.len = 0;
record.flags &= ~Record::HAS_ATTR;
return 0;
}
}