muduo库分析——net篇(6)Buffer
程序员文章站
2022-06-14 10:18:01
...
参考MuduoManual
为什么要有应用层Buffer?
前面prependable是预留空间,有一些控制信息,比如说后面有多少字节,或者一些数据的校验码等等可以直接放在这里,而不需要重新分配空间进行内容复制,这是一种空间换时间的方法
中间readable是可读的信息,表示这里的数据没有读取取出
后面writable是可写的空间,表示这里的空间还没有数据写入
在TcpConnection.h中可以看见有两个Buffer成员,input是用户用于从socket中读取数据,output是用户往socket中写出数据
其他函数都是指针相关的操作或者数据的拷贝,没有什么困难的地方
这是从socket中读取所有数据,内核态的socket缓冲区大小默认接受64k和发送64k的话(可以更改),那么两个Buffer需要写成固定大小64k字节,但是一般来说这么大的空间很少用到,我们可以利用vector的resize功能,将数据慢慢变大,因为不知道socket有多少数据,readFd为了一次性读完socket中的数据(虽然这是LT模式,但为了方便起见),建立了一个临时的栈上空间char extrabuf[65536],假如vector<char>中的可用空间够大了(大于64k),那么肯定可以一次性读取完成所有的数据,否则就加上这个临时空间一起去读取socket数据。
这样做的好处是既能一次性读取完socket的数据,又能避免一开始建立的TcpConnection占用空间过大,一次性读完可以避免重复调用读取导致系统开销过大
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;//两块一起读取或者只用buffer空间读取
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);
}
// if (n == writable + sizeof extrabuf)
// {
// goto line_30;
// }
return n;
}
Buffer不是线程安全,但是也不存在其他线程会对其进行读写,因为其所属TcpConnection属于一个io线程,只有该io线程才能调用TcpConnection相关函数