• 序列化容器—二进制编码与解码


    0 前言

         在rpc或分布式节点间的通讯框架里面,我们经常会有“业务数据与二进制流数据之间进行编码或解码转换”的场景要求,在jdk的nio框架里面有既有的ByteBuffer类满足此需求,那么在c++里面,同样我们简单看看,一个具有类似功能的类DataBuffer。  

    1 实现机制

         其实现机制:通过指针偏移指向同一块内存,分别表示内存的起始与结束偏移位置,分别表示读与写的偏移位置。如下图:  

    2 操作步骤

       2.1 读取数据时,仅需偏移_pdata即可

           源码如下:

        bool readBytes(void *dst, int len) {
    
            if (_pdata + len > _pfree) {
    
                return false;
    
            }
    
            memcpy(dst, _pdata, len);
    
            _pdata += len;
    
            assert(_pfree>=_pdata);
    
            return true;
    
        }
    View Code

       2.2 写数据时,仅需偏移_pfree指针即可

           源码如下:             

      void writeString(const char *str) {
    
            int len = (str ? static_cast<int32_t>(strlen(str)) : 0);
    
            if (len>0) len ++;
    
            expand(static_cast<int32_t>(len+sizeof(uint32_t)));
    
            writeInt32(len);
    
            if (len>0) {
    
                memcpy(_pfree, str, len);
    
                _pfree += (len);
    
            }
    
        }
    View Code

        2.3 当所需内存不足时(_ppend - _pfree < need ),干两件事情:

            a 申请新的当前于内存空间2倍的内存(<<= 1)

            b 把已有数据拷贝至新的内存块上

           源码如下:

    inline void expand(int need) {
    
            if (_pstart == NULL) {
    
                int len = 256;
    
                while (len < need) len <<= 1;
    
                _pfree = _pdata = _pstart = (unsigned char*)malloc(len);
    
                _pend = _pstart + len;
    
            } else if (_pend - _pfree < need) { // 空间不够
    
                int flen = static_cast<int32_t>((_pend - _pfree) + (_pdata - _pstart));
    
                int dlen = static_cast<int32_t>(_pfree - _pdata);
    
     
    
                if (flen < need || flen * 4 < dlen) {
    
                    int bufsize = static_cast<int32_t>((_pend - _pstart) * 2);
    
                    while (bufsize - dlen < need)
    
                        bufsize <<= 1;
    
     
    
                    unsigned char *newbuf = (unsigned char *)malloc(bufsize);
    
                    if (newbuf == NULL)
    
                    {
    
                      TBSYS_LOG(ERROR, "expand data buffer failed, length: %d", bufsize);
    
                    }
    
                    assert(newbuf != NULL);
    
                    if (dlen > 0) {
    
                        memcpy(newbuf, _pdata, dlen);
    
                    }
    
                    free(_pstart);
    
     
    
                    _pdata = _pstart = newbuf;
    
                    _pfree = _pstart + dlen;
    
                    _pend = _pstart + bufsize;
    
                } else {
    
                    memmove(_pstart, _pdata, dlen);
    
                    _pfree = _pstart + dlen;
    
                    _pdata = _pstart;
    
                }
    
            }
    
        }
    View Code

    3 实例

    3.1 输入

    3.2 输出

       out1: 11 out2: 1100 out3: hello world

        源码请见 http://files.cnblogs.com/files/gisorange/databuffer.zip

      

  • 相关阅读:
    大一励志的我,现在已经大三了
    Jenkins+K8s实现持续集成
    Jenkins搭建自动化测试环境
    软件开发式样书 6
    软件开发式样书 5
    软件开发式样书 4
    软件开发式样书 3
    软件开发式样书 2
    软件开发式样书 1
    Git学习笔记
  • 原文地址:https://www.cnblogs.com/gisorange/p/4891059.html
Copyright © 2020-2023  润新知