收藏 分享(赏)

C++ 缓存设计.doc

上传人:11xg27ws 文档编号:7560680 上传时间:2019-05-21 格式:DOC 页数:31 大小:125.50KB
下载 相关 举报
C++ 缓存设计.doc_第1页
第1页 / 共31页
C++ 缓存设计.doc_第2页
第2页 / 共31页
C++ 缓存设计.doc_第3页
第3页 / 共31页
C++ 缓存设计.doc_第4页
第4页 / 共31页
C++ 缓存设计.doc_第5页
第5页 / 共31页
点击查看更多>>
资源描述

1、以 windows IOCP 为例,complete 线程在接收到数据后,应该马上将接收到的数据拷贝到解包缓存,然后立即发起一次新的 WSARecv 操作。然后再对解包缓存执行操作,解析出逻辑包。通常的方法是将数据拷贝到一个环形缓冲中,以减少数据的拷贝次数。但在解出一个数据包之后,免不了还要将一个完整的数据包拷贝到另一个包缓存中,再将这个包提交给应用层处理.本文介绍一种,拼包方式,以避免从解包缓存 copy 数据到逻辑包中.首先介绍逻辑包的组织结构:/RPacket 数据可跨越多个 bufferclass RPacketfriend class Connection;friend class

2、WPacket;public:RPacket(const RPacket bool _nil()return m_buf._nil();RPacketm_head = other.m_head;m_len = other.m_len;m_buf = other.m_buf;m_readPos = other.m_readPos;if(m_binBuffer)delete m_binBuffer;m_binBufferPos = 0;return *this;char ReadChar()return Read();short ReadShort()return Read();long Read

3、Long()return Read();float ReadFloat()return Read();double ReadDouble()return Read();short ReadCmd()return *(short*)const char* ReadString()unsigned int strLen = (unsigned int)Read();if(strLen = 0 | m_dataRemain m_bufSize - m_readPos;/当前 buf 还有多少有效数据char *str;if(sizeRemain = strLen) str = m_readPos +

4、= strLen;elseif(!m_binBuffer)m_binBuffer = new charm_len;m_binBufferPos = 0;str = unsigned int copySize = sizeRemain;memcpy(m_readBuf = m_readBuf-m_next;m_readPos = 0;m_binBufferPos += copySize;copySize = strLen - copySize;memcpy(m_readPos += copySize;m_dataRemain -= strLen;Arrange();return str;cons

5、t void* ReadBinary(unsigned short if(len = 0 | m_dataRemain m_bufSize - m_readPos;/当前 buf 还有多少有效数据if(sizeRemain = len)bin = m_readPos += len;elseif(!m_binBuffer)m_binBuffer = new charm_len;m_binBufferPos = 0;bin = unsigned int copySize = sizeRemain;memcpy(m_readBuf = m_readBuf-m_next;m_readPos = 0;m

6、_binBufferPos += copySize;copySize = len - copySize;memcpy(m_readPos += copySize;m_dataRemain -= len;Arrange();return bin;private:template T Read()if(m_readBuf._nil()return 0;unsigned int TypeSize = sizeof(T);if(m_dataRemain = TypeSize)ret = *(T*)m_readPos += TypeSize;else/数据跨越了两个数据块char tmpsizeof(T

7、);char *ptr = tmp;unsigned int copySize = sizeRemain;memcpy(ptr += copySize;copySize = TypeSize - copySize;m_readBuf = m_readBuf-m_next;m_readPos = 0;memcpy(m_readPos += copySize;ret = *(T*)m_dataRemain -= TypeSize;Arrange();return ret;RPacket(rptr void Arrange()if(m_readPos = m_readBuf-m_bufSize m_

8、readBuf = m_readBuf-m_next;private:unsigned short m_readPos;unsigned short m_head; /在 buf 中的起始下标unsigned short m_len; /packet 的总长度unsigned short m_dataRemain;/用于处理 ReadString,和 ReadBin 时数据跨越 buffer 的情况char * m_binBuffer;unsigned short m_binBufferPos;/rptr m_readBuf;/当前 readPos 所在的 bufrptr m_buf;/存放

9、packet 的数据,可能由一组 m_buf 构成链表;复制代码如代码所示,数据存放在由 m_buf 组成的 list 中,m_head 表明属于本RPacket 的数据在 m_buf 中的起始位置.一个 buf 块的大小为 65535 字节。如果包的长度不大,则 N 个 RPacket 可以共享同一个 buf,如果 RPacket 的数据大于 65535,则一个 RPacket 的数据则可能会使用超过一块 buf。由同一个套接口收到的所有 RPacket,其实际数据被一个 buf 链表链接着。buf 由基于引用计数的指针指向,当引用同一个 buf 块的 RPacket 都被释放之后,buf

10、也将会被释放。下面介绍数据接收和解包处理过程:bool Connection:Recv()if(m_tail._nil()m_CurRecvBuf = m_head = m_tail = new buffer(MAX_PACKET_SIZE);m_pos = m_totalDataSize = m_writePos = 0;unsigned short bufCount = 0;unsigned short RecvSize = MAX_PACKET_SIZE;unsigned short freeBufSize = m_CurRecvBuf-m_bufSize - m_writePos;m_

11、WRecvBufbufCount.buf = m_WRecvBufbufCount.len = freeBufSize;RecvSize -= freeBufSize;if(RecvSize 0)+bufCount;/不够 MAX_PACKET_SIZErptr tmp = new buffer(MAX_PACKET_SIZE);m_tail-m_next = tmp;m_tail = tmp;m_WRecvBufbufCount.buf = m_WRecvBufbufCount.len = RecvSize;return ConnectionBase:Recv(m_WRecvBuf,bufC

12、ount,(OVERLAPPED*)void Connection:OnRecvComplete(unsigned short dwBytesTransfered)unsigned short freeBufSize = m_CurRecvBuf-m_bufSize - m_writePos;if(freeBufSize = dwBytesTransfered)m_writePos += dwBytesTransfered;freeBufSize -= dwBytesTransfered;m_CurRecvBuf-m_dataSize += dwBytesTransfered;if(freeB

13、ufSize tmp = new buffer(MAX_PACKET_SIZE);m_tail-m_next = tmp;m_tail = tmp;m_CurRecvBuf = m_tail;m_writePos = 0;elsem_CurRecvBuf-m_dataSize = m_CurRecvBuf-m_bufSize;/开辟新空间rptr tmp = new buffer(MAX_PACKET_SIZE);m_tail-m_next = tmp;m_tail = tmp;m_CurRecvBuf = m_tail;m_writePos += (dwBytesTransfered - f

14、reeBufSize);m_CurRecvBuf-m_dataSize += (dwBytesTransfered - freeBufSize);m_totalDataSize += dwBytesTransfered;/Recv();RPacket Connection:UnPack()if(!m_head._nil()return RPacket(rptr(0),0);unsigned short packetLen = ReadPacketLen();if(packetLen = 0)return RPacket(rptr(0),0);if(m_totalDataSize (0),0);

15、/没有足够的数据/OK,数据充足,返回封包RPacket rpk(m_head,(unsigned short)m_pos);m_totalDataSize -= packetLen;/调整 m_head 和 m_posm_pos += packetLen;while(m_pos = MAX_PACKET_SIZE)rptr tmp = m_head;m_head = m_head-m_next;if(m_head._nil()m_tail = 0;m_pos = 0;elsem_pos -= MAX_PACKET_SIZE;return rpk;复制代码完成例程在 OnRecvComplet

16、e 中,把接收到的数据拷贝到 buf 链表中,马上启动新的 Recv 操作.后续的解包过程是 UnPack 函数,其作用就是将 buf 链表中的数据解包,并将RPacket 返回以供应用层处理,从代码中可以看出,解包过程是没有数据拷贝的,只需要正确设置RPacket 中的字段就可以了.基于 QT C+的网络缓冲区设计(一) 概括 缓冲区的关键是: 字符串数据 和 类型数据 之间的相互转换。比如将 char *的数据的按 1byte 1 byte 的读入转化为bool、char 、uint8 、int16、uint16 、int32(相当于 int),uint32、int64(相当于 long

17、long);当然还有 double。网络缓冲区分为发送端 和 接收端。发送端将类型数据 转换为 字符串数据。 接收端将字符数据 转换为 类型数据。一、发送端#ifndef SMPEnplexer_H #define SMPEnplexer_H#include “SMP_COMMAND.h“class SMPEnplexerpublic:SMPEnplexer(unsigned bufsize=8192); /default is 8KBSMPEnplexer();char* data() return _data;unsigned length() return _pos;void setLe

18、ngth(int pos)_pos += pos;void setBufferSize(int size);unsigned buffersize()return _bufSize;void reset();void addHead();/ add a argumentvoid addBoolArg(bool value);void addCharArg(char value);void addUInt8Arg(unsigned char value);void addInt16Arg(short value);void addUInt16Arg(short value) addInt16Ar

19、g(value); ;void addInt32Arg(int value);void addUInt32Arg(unsigned value) addInt32Arg(value); ;void addInt64Arg(long long int value);void addUInt64Arg(long long unsigned value) addInt64Arg(value); ;void addFloatArg(float value);void addStringArg(const QString void addCharArray(char* str,int len);PACK

20、AGE_HEAD head;protected:unsigned _bufSize;char *_data;unsigned _pos;QTextCodec* codec;#endif / SMPEnplexer_H二、接收端接收端将字符串数据流 转换为 相应的类型数据。#ifndef SMPDeplexer_H #define SMPDeplexer_H#include #include “SMP_COMMAND.h“class SMPDeplexerpublic:SMPDeplexer(unsigned bufSize = 4096);SMPDeplexer();char *data()

21、return _data;unsigned length() return _length;void setLength(int len) _length = len;unsigned buffersize() return _bufSize;void setBufferSize(unsigned size);void reset();/ demultiplex the next arg in the streambool boolArg();char charArg();unsigned char uint8Arg();short int16Arg();unsigned short uint

22、16Arg() return int16Arg(); int int32Arg();unsigned uint32Arg() return int32Arg(); long long int int64Arg();long long unsigned uint64Arg() return int64Arg(); void deplexHead();void deplexCharArray(char* str,int len);char *_data;unsigned _pos;unsigned _bufSize;unsigned _length;QTextCodec* codec;PACKAG

23、E_HEAD head;#endif / SMPDeplexer_H多字节与 UTF-8、Unicode 之间的转换 1.2.3. / 多字节编码转为 UTF8 编码 4. bool MBToUTF8(vector 8. 9. WCHAR* lpszW = NULL; 10. try 11. 12. lpszW = new WCHARnLen; 13. 14. catch(bad_alloc 17. 18. 19. int32 nRtn = MultiByteToWideChar(CP_ACP, 0, pmb, mLen, lpszW, nLen); 20. 21. if(nRtn != nL

24、en) 22. 23. delete lpszW; 24. return false; 25. 26. / convert an widechar string to utf8 27. int32 utf8Len = WideCharToMultiByte(CP_UTF8, 0, lpszW, nLen, NULL, 0, NULL, NULL); 28. if (utf8Len 49. 50. WCHAR* lpszW = NULL; 51. try 52. 53. lpszW = new WCHARnLen; 54. 55. catch(bad_alloc 58. 59. 60. int3

25、2 nRtn = MultiByteToWideChar(CP_UTF8, 0, pu8, utf8Len, lpszW, nLen); 61. 62. if(nRtn != nLen) 63. 64. delete lpszW; 65. return false; 66. 67. 68. / convert an widechar string to Multibyte 69. int32 MBLen = WideCharToMultiByte(CP_ACP, 0, lpszW, nLen, NULL, 0, NULL, NULL); 70. if (MBLen 91. 92. if (uL

26、en 113. if (MBLen 133. if (nLen 154. if (utf8Len();short ReadShort()return Read();long ReadLong()return Read();float ReadFloat()return Read();double ReadDouble()return Read();short ReadCmd()return *(short*)const char* ReadString()unsigned int strLen = (unsigned int)Read();if(strLen = 0 | m_dataRemai

27、n m_bufSize - m_readPos;/当前 buf 还有多少有效数据char *str;if(sizeRemain = strLen) str = m_readPos += strLen;elseif(!m_binBuffer)m_binBuffer = new charm_len;m_binBufferPos = 0;str = unsigned int copySize = sizeRemain;memcpy(m_readBuf = m_readBuf-m_next;m_readPos = 0;m_binBufferPos += copySize;copySize = strL

28、en - copySize;memcpy(m_readPos += copySize;m_dataRemain -= strLen;Arrange();return str;const void* ReadBinary(unsigned short if(len = 0 | m_dataRemain m_bufSize - m_readPos;/当前 buf 还有多少有效数据if(sizeRemain = len)bin = m_readPos += len;elseif(!m_binBuffer)m_binBuffer = new charm_len;m_binBufferPos = 0;b

29、in = unsigned int copySize = sizeRemain;memcpy(m_readBuf = m_readBuf-m_next;m_readPos = 0;m_binBufferPos += copySize;copySize = len - copySize;memcpy(m_readPos += copySize;m_dataRemain -= len;Arrange();return bin;private:template T Read()if(m_readBuf._nil()return 0;m_next;m_readPos = 0;memcpy(m_read

30、Pos += copySize;ret = *(T*)m_dataRemain -= TypeSize;Arrange();return ret;RPacket(rptr void Arrange()if(m_readPos = m_readBuf-m_bufSize m_readBuf = m_readBuf-m_next;private:unsigned short m_readPos;unsigned short m_head; /在 buf 中的起始下标unsigned short m_len; /packet 的总长度unsigned short m_dataRemain;/用于处理

31、 ReadString,和 ReadBin 时数据跨越 buffer 的情况char * m_binBuffer;unsigned short m_binBufferPos;/rptr m_readBuf;/当前 readPos 所在的 bufrptr m_buf;/存放 packet 的数据,可能由一组 m_buf 构成链表;如代码所示,数据存放在由 m_buf 组成的 list 中,m_head 表明属于本RPacket 的数据在 m_buf 中的起始位置.一个 buf 块的大小为 65535 字节。如果包的长度不大,则 N 个 RPacket 可以共享同一个 buf,如果 RPacket

32、 的数据大于 65535,则一个 RPacket 的数据则可能会使用超过一块 buf。由同一个套接口收到的所有 RPacket,其实际数据被一个 buf 链表链接着。buf 由基于引用计数的指针指向,当引用同一个 buf 块的 RPacket 都被释放之后,buf 也将会被释放。下面介绍数据接收和解包处理过程:bool Connection:Recv()if(m_tail._nil()m_CurRecvBuf = m_head = m_tail = new buffer(MAX_PACKET_SIZE);m_pos = m_totalDataSize = m_writePos = 0;unsi

33、gned short bufCount = 0;unsigned short RecvSize = MAX_PACKET_SIZE;unsigned short freeBufSize = m_CurRecvBuf-m_bufSize - m_writePos;m_WRecvBufbufCount.buf = m_WRecvBufbufCount.len = freeBufSize;RecvSize -= freeBufSize;if(RecvSize 0)+bufCount;/不够 MAX_PACKET_SIZErptr tmp = new buffer(MAX_PACKET_SIZE);m

34、_tail-m_next = tmp;m_tail = tmp;m_WRecvBufbufCount.buf = m_WRecvBufbufCount.len = RecvSize;return ConnectionBase:Recv(m_WRecvBuf,bufCount,(OVERLAPPED*)void Connection:OnRecvComplete(unsigned short dwBytesTransfered)unsigned short freeBufSize = m_CurRecvBuf-m_bufSize - m_writePos;if(freeBufSize = dwB

35、ytesTransfered)m_writePos += dwBytesTransfered;freeBufSize -= dwBytesTransfered;m_CurRecvBuf-m_dataSize += dwBytesTransfered;if(freeBufSize tmp = new buffer(MAX_PACKET_SIZE);m_tail-m_next = tmp;m_tail = tmp;m_CurRecvBuf = m_tail;m_writePos = 0;elsem_CurRecvBuf-m_dataSize = m_CurRecvBuf-m_bufSize;/开辟

36、新空间rptr tmp = new buffer(MAX_PACKET_SIZE);m_tail-m_next = tmp;m_tail = tmp;m_CurRecvBuf = m_tail;m_writePos += (dwBytesTransfered - freeBufSize);m_CurRecvBuf-m_dataSize += (dwBytesTransfered - freeBufSize);m_totalDataSize += dwBytesTransfered;/Recv();RPacket Connection:UnPack()if(!m_head._nil()retur

37、n RPacket(rptr(0),0);unsigned short packetLen = ReadPacketLen();if(packetLen = 0)return RPacket(rptr(0),0);if(m_totalDataSize (0),0);/没有足够的数据/OK,数据充足,返回封包RPacket rpk(m_head,(unsigned short)m_pos);m_totalDataSize -= packetLen;/调整 m_head 和 m_posm_pos += packetLen;while(m_pos = MAX_PACKET_SIZE)rptr tmp = m_head;m_head = m_head-m_next;if(m_head._nil()

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报