非阻塞的网络编程中,在应用层都需要使用Buffer,具体原因见这里。
Buffer的作用就是暂时存储数据。当向Buffer写入数据后,Buffer可写入空间减小,可读空间增大;取走数据后变化相反。
muduo中的Buffer为封装了的vector。vector为一块连续空间,且其本身具有自动增长的性质,它的迭代器为原始指针,使用起来较为方便。Buffer的结构如下图:
两个readIndex和writeIndex把vector的内容分为三块:prependable、readable、writable。
prependable为前缀空间,在使用TLV格式时比较方便。
readable为可读空间,里面放有缓存的数据。
writeable为可写空间。
各个空间大小计算公式为:
prependable = readIndex
readable = writeIndex - readIndex
writable = size() - writeIndex
Buffer没有封装为一个环,所以当Buffer使用一段时间后,其真正的可写入空间不一定是size() - writeIndex,因为readIndex和prependable之间可能还有空间。因此当可写如空间不够时,有时可以通过把CONTENT向“前移”来达到目的。当向前移还不能满足时,才真正开辟新空间。
从fd读数据到Buffer中时,因为不知道一次性可以读多少,因此在栈上开辟了65536字节的空间extrabuf,使用readv读取。如果Buffer中wriable足够存放从fd读到的数据,则读取完毕;否则剩余数据读到extrabuf中,再将其添加到Buffer中。
Buffer.h
/// +-------------------+------------------+------------------+
/// | prependable bytes | readable bytes | writable bytes |
/// | | (CONTENT) | |
/// +-------------------+------------------+------------------+
/// | | | |
/// 0 <= readerIndex <= writerIndex <= size
/// @endcode
class Buffer : public muduo::copyable
{
public:
static const size_t kCheapPrepend = 8;//前面预留空间大小
static const size_t kInitialSize = 1024;//初始化存储数据空间
explicit Buffer(size_t initialSize = kInitialSize)
: buffer_(kCheapPrepend + initialSize),//初始化Buffer总大小
readerIndex_(kCheapPrepend),
writerIndex_(kCheapPrepend)
{
assert(readableBytes() == 0);
assert(writableBytes() == initialSize);
assert(prependableBytes() == kCheapPrepend);
}
// implicit copy-ctor, move-ctor, dtor and assignment are fine
// NOTE: implicit move-ctor is added in g++ 4.6
void swap(Buffer& rhs)
{
buffer_.swap(rhs.buffer_);
std::swap(readerIndex_, rhs.readerIndex_);
std::swap(writerIndex_, rhs.writerIndex_);
}
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_; }
const char* findCRLF() const//在[peek(), beginWrite())中找\r\n
{
// FIXME: replace with memmem()?
const char* crlf = std::search(peek(), beginWrite(), kCRLF, kCRLF+2);
return crlf == beginWrite() ? NULL : crlf;
}
const char* findCRLF(const char* start) const//从位置start开始查找
{
assert(peek() <= start);
assert(start <= beginWrite());
// FIXME: replace with memmem()?
const char* crlf = std::search(start, beginWrite(), kCRLF, kCRLF+2);
return crlf == beginWrite() ? NULL : crlf;
}
const char* findEOL() const//查找'\n'的位置
{
const void* eol = memchr(peek(), '\n', readableBytes());
return static_cast<const char*>(eol);
}
const char* findEOL(const char* start) const
{
assert(peek() <= start);
assert(start <= beginWrite());
const void* eol = memchr(start, '\n', beginWrite() - start);
return static_cast<const char*>(eol);
}
// retrieve returns void, to prevent
// string str(retrieve(readableBytes()), readableBytes());
// the evaluation of two functions are unspecified
void retrieve(size_t len)//取走len长度数据,主要在于设置readerIndex_和writerIndex_的值
{
assert(len <= readableBytes());
if (len < readableBytes())
{
readerIndex_ += len;
}
else
{
retrieveAll();//全部取走
}
}
void retrieveUntil(const char* end)//end前的数据全取走
{
assert(peek() <= end);
assert(end <= beginWrite());
retrieve(end - peek());
}
void retrieveInt64()
{
retrieve(sizeof(int64_t));
}
void retrieveInt32()
{
retrieve(sizeof(int32_t));
}
void retrieveInt16()
{
retrieve(sizeof(int16_t));
}
void retrieveInt8()
{
retrieve(sizeof(int8_t));
}
void retrieveAll()
{
readerIndex_ = kCheapPrepend;
writerIndex_ = kCheapPrepend;
}
string retrieveAllAsString()//Buffer中所有数据以字符串形式取走
{
return retrieveAsString(readableBytes());;
}
string retrieveAsString(size_t len)//Buffer中len长度数据以字符串形式取走
{
assert(len <= readableBytes());
string result(peek(), len);
retrieve(len);
return result;
}
StringPiece toStringPiece() const
{
return StringPiece(peek(), static_cast<int>(readableBytes()));
}
void append(const StringPiece& str)
{
append(str.data(), str.size());
}
void append(const char* /*restrict*/ data, size_t len)
{
ensureWritableBytes(len);
std::copy(data, data+len, beginWrite());
hasWritten(len);
}
void append(const void* /*restrict*/ data, size_t len)
{
append(static_cast<const char*>(data), len);
}
void ensureWritableBytes(size_t len)//确保Buffer中可以写入len长度数据
{
if (writableBytes() < len)//可写入空间不够大
{
makeSpace(len);//确保可写入空间不小于len
}
assert(writableBytes() >= len);
}
char* beginWrite()//返回指向可写入位置的指针
{ return begin() + writerIndex_; }
const char* beginWrite() const
{ return begin() + writerIndex_; }
void hasWritten(size_t len)//写入len长度数据后,调用本函数
{
assert(len <= writableBytes());
writerIndex_ += len;
}
void unwrite(size_t len)//撤销最后写入的len长度数据
{
assert(len <= readableBytes());
writerIndex_ -= len;
}
///
/// Append int64_t using network endian
///
void appendInt64(int64_t x)
{
int64_t be64 = sockets::hostToNetwork64(x);
append(&be64, sizeof be64);
}
///
/// Append int32_t using network endian
///
void appendInt32(int32_t x)
{
int32_t be32 = sockets::hostToNetwork32(x);
append(&be32, sizeof be32);
}
void appendInt16(int16_t x)
{
int16_t be16 = sockets::hostToNetwork16(x);
append(&be16, sizeof be16);
}
void appendInt8(int8_t x)
{
append(&x, sizeof x);
}
///
/// Read int64_t from network endian
///
/// Require: buf->readableBytes() >= sizeof(int32_t)
int64_t readInt64()
{
int64_t result = peekInt64();
retrieveInt64();
return result;
}
///
/// Read int32_t from network endian
///
/// Require: buf->readableBytes() >= sizeof(int32_t)
int32_t readInt32()
{
int32_t result = peekInt32();
retrieveInt32();
return result;
}
int16_t readInt16()
{
int16_t result = peekInt16();
retrieveInt16();
return result;
}
int8_t readInt8()
{
int8_t result = peekInt8();
retrieveInt8();
return result;
}
///
/// Peek int64_t from network endian
///
/// Require: buf->readableBytes() >= sizeof(int64_t)
int64_t peekInt64() const//从Buffer中读Int64长度数据并返回此数据
{
assert(readableBytes() >= sizeof(int64_t));
int64_t be64 = 0;
::memcpy(&be64, peek(), sizeof be64);
return sockets::networkToHost64(be64);
}
///
/// Peek int32_t from network endian
///
/// Require: buf->readableBytes() >= sizeof(int32_t)
int32_t peekInt32() const
{
assert(readableBytes() >= sizeof(int32_t));
int32_t be32 = 0;
::memcpy(&be32, peek(), sizeof be32);
return sockets::networkToHost32(be32);
}
int16_t peekInt16() const
{
assert(readableBytes() >= sizeof(int16_t));
int16_t be16 = 0;
::memcpy(&be16, peek(), sizeof be16);
return sockets::networkToHost16(be16);
}
int8_t peekInt8() const
{
assert(readableBytes() >= sizeof(int8_t));
int8_t x = *peek();
return x;
}
///
/// Prepend int64_t using network endian
///
void prependInt64(int64_t x)//向前缀写数据
{
int64_t be64 = sockets::hostToNetwork64(x);
prepend(&be64, sizeof be64);
}
///
/// Prepend int32_t using network endian
///
void prependInt32(int32_t x)
{
int32_t be32 = sockets::hostToNetwork32(x);
prepend(&be32, sizeof be32);
}
void prependInt16(int16_t x)
{
int16_t be16 = sockets::hostToNetwork16(x);
prepend(&be16, sizeof be16);
}
void prependInt8(int8_t x)
{
prepend(&x, sizeof x);
}
void prepend(const void* /*restrict*/ data, size_t len)//把从data开始,长度为len的数据加到前缀
{
assert(len <= prependableBytes());
readerIndex_ -= len;
const char* d = static_cast<const char*>(data);
std::copy(d, d+len, begin()+readerIndex_);
}
void shrink(size_t reserve)//更改Buffer的大小,使其可写入空间为reserve大小
{
// FIXME: use vector::shrink_to_fit() in C++ 11 if possible.
Buffer other;
other.ensureWritableBytes(readableBytes()+reserve);
other.append(toStringPiece());
swap(other);
}
size_t internalCapacity() const
{
return buffer_.capacity();
}
/// Read data directly into buffer.
///
/// It may implement with readv(2)
/// @return result of read(2), @c errno is saved
ssize_t readFd(int fd, int* savedErrno);
private:
char* begin()//返回Buffer的起始地址
{ return &*buffer_.begin(); }
const char* begin() const
{ return &*buffer_.begin(); }
void makeSpace(size_t len)//resize或移动数据,使Buffer能容下len大数据
{
if (writableBytes() + prependableBytes() < len + kCheapPrepend)//Buffer总的空间不够大
{
// 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
begin()+writerIndex_,//end
begin()+kCheapPrepend);//destination
readerIndex_ = kCheapPrepend;
writerIndex_ = readerIndex_ + readable;
assert(readable == readableBytes());
}
}
private:
std::vector<char> buffer_;//连续内存
size_t readerIndex_;//可读起始位置
size_t writerIndex_;//可写入起始位置
static const char kCRLF[];//存储匹配串内容
};
Buffer.cc
const char Buffer::kCRLF[] = "\r\n";
const size_t Buffer::kCheapPrepend;
const size_t Buffer::kInitialSize;
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)//Buffer中可以存储所有读到的数据
{
writerIndex_ += n;
}
else//读的数据太多,部分存储到了extrabuf
{
writerIndex_ = buffer_.size();
append(extrabuf, n - writable);
}