美文网首页
muduo 源码阅读:Buffer

muduo 源码阅读:Buffer

作者: wayyyy | 来源:发表于2021-03-17 23:01 被阅读0次

    为什么non-blocking 网络编程中应用层Buffer是必须的?

    TODO

    Buffer 数据结构

    class Buffer
    {
    public:
        static const size_t kCheapPrepend = 8;
        static const size_t kInitialSize = 1024;
    public:
    private:
        std::vector<char> buffer_;
        size_t readerIndex_;
        size_t writerIndex_;
    };
    
    image.png
    • 为什么 readerIndex_writerIndex_int,不是 char* ?
      应对迭代器失效

    • readerIndex_ 和 writeIndex_ 满足不变式
      0 \leq readindex \leq writeIndex \leq size()

    • 底层为什么采用std::vector

      • 内存自动增长
      • 指数增长的内存减少内存分配次数
      • size() 自适应

    Buffer 操作

    size_t readableBytes() const {  return writerIndex_ - readerIndex_;  }
    size_t writableBytes() const  {  return buffer_.size() - writerIndex_;  }
    size_t prependableBytes() const  {  return readerIndex_;  }
    const char *peek() const  {  return begin() + readerIndex_;  }
    char *beginWrite()  {  return begin() + writerIndex_;  }
    
    写入数据
    void appendInt32(int32_t x)
    {
        int32_t be32 = sockets::hostToNetwork32(x);
        append(&be32, sizeof(be32));
    }
    
    void append(const void * /*restrict*/ data, size_t len)
    {
        append(static_cast<const char *>(data), len);
    }
    
    void append(const char * /*restrict*/ data, size_t len)
    {
        ensureWritableBytes(len);
        std::copy(data, data + len, beginWrite());
        hasWritten(len);
    }
    
    void ensureWritableBytes(size_t len)
    {
        if (writableBytes() < len)
        {
            makeSpace(len);
        }
        assert(writableBytes() >= len);
    }
    
    void makeSpace(size_t len)
    {
        if (writableBytes() + prependableBytes() < len + kCheapPrepend)
        {
             // FIXME: move readable data
             buffer_.resize(writerIndex_ + len);
        }
        else
        {
            // move readable data to the front, make space inside buffer
            assert(kCheapPrepend < readerIndex_);
            size_t readable = readableBytes();
            std::copy(begin() + readerIndex_, 
                      begin() + writerIndex_, 
                      begin() + kCheapPrepend);
            readerIndex_ = kCheapPrepend;
            writerIndex_ = readerIndex_ + readable;
            assert(readable == readableBytes());
        }
    }
    
    void hasWritten(size_t len)
    {
        assert(len <= writableBytes());
        writerIndex_ += len;
    }
    
    • 内部腾挪
      有时候,经过若干次读写,当readIndex_移动到了比较靠后的位置,留下了巨大的prependable空间。

      image.png

      如图所示:这时如果我们想写入300字节,而writeable只有200字节,这时,Buffer 并不会重新分配内存。而是把已有的数据移动到前面去。腾出writeable空间

      image.png
    • std::vector resize 和 reserve 区别 ?

      • reserver函数用来给vector预分配存储区大小,即capacity的值 ,但是没有给这段内存进行初始化。
      • resize函数重新分配大小,改变容器的大小,并且创建对象
        • 当 n 小于当前 size() 值时候,vector 首先会减少 size() 值 保存前 n 个元素,然后将超出 n 的元素删除 (remove and destroy)
        • 当 n 大于当前 size() 值时候,vector 会插入相应数量的元素 使得 size() 值达到 n,并对这些元素进行初始化,如果调用上面的第二个 resize 函数,指定 val,vector 会用 val 来初始化这些新插入的元素
        • 当 n 大于 capacity() 值的时候,会自动分配重新分配内存存储空间。
    读取数据
    int32_t readInt32()
    {
        int32_t result = peekInt32();
        retrieveInt32();
        return result;
    }
    
    void retrieveInt32()
    {
        retrieve(sizeof(int32_t));
    }     
    
    void retrieve(size_t len)
    {
        assert(len <= readableBytes());
        if (len < readableBytes()) 
        {
            readerIndex_ += len;
        }
        else  // len == readableBytes()
        {
            retrieveAll();
        }
    }
    
    void retrieveAll()
    {
        readerIndex_ = kCheapPrepend;
        writerIndex_ = kCheapPrepend;
    }
    

    prehead

    readFd

    ssize_t Buffer::readFd(int fd, int* savedErrno)
    {
        // saved an ioctl()/FIONREAD call to tell how much to read
        char extrabuf[65536];
        struct iovec vec[2];
        const size_t writable = writableBytes();
        vec[0].iov_base = begin()+writerIndex_;
        vec[0].iov_len = writable;
        vec[1].iov_base = extrabuf;
        vec[1].iov_len = sizeof extrabuf;
        // when there is enough space in this buffer, don't read into extrabuf.
        // when extrabuf is used, we read 128k-1 bytes at most.
        const int iovcnt = (writable < sizeof extrabuf) ? 2 : 1;
        const ssize_t n = sockets::readv(fd, vec, iovcnt);
        if (n < 0)
        {
            *savedErrno = errno;
        }
        else if (implicit_cast<size_t>(n) <= writable)
        {
          writerIndex_ += n;
        }
        else
        {
          writerIndex_ = buffer_.size();
          append(extrabuf, n - writable);
        }
        
        return n;
    }
    

    相关文章

      网友评论

          本文标题:muduo 源码阅读:Buffer

          本文链接:https://www.haomeiwen.com/subject/xjxjwktx.html