Buffer
这里的Buffer类是参考陈硕大佬的Linux多线程服务端编程
。
首先,我们为什么要设计buffer:
减少系统调用
,频繁从用户态切换到内核态,会浪费大量的cpu时间。
流量控制
,使得网络通信的速度和处理速度之间能够更好地匹配。
数据完整性
在网络传输中,数据可能会分多次到达。缓冲区可以将这些分片的数据收集完整,然后再通知应用程序处理完整的数据。
那么,我们要尽可能的在一次系统调用中读取最多的数据,减少系统调用
。同时,我们还需要考虑内存问题,让buffer缓冲区
又不至于占用过多内存。
由于调用Buffer的用户是线程安全或只有一个线程对Buffer进行操作,且buffer内的操作不会产生竞态。也就是说我们的Buffer不是线程安全的
,线程安全性的责任被传递给了调用者
。
在muduo
库里,由buffer
和extrabuffer
组成接收数据的缓冲区,其中extrabuffer
是局部变量,用于存储额外的数据,尽可能读取更多数据。当extrabuffer
有数据时,我们把他append
到vector里。
muduo库buffer的快速了解,建议认真阅读muduo学习笔记:net部分之实现TCP网络编程库-Buffer_muduo::net::buffer-CSDN博客
buffer.h
为了锻炼自己的编程能力,我们作为cv
工程师就直接先来写.h头文件,再自己实现.cpp文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| #ifndef BUFFER_H #define BUFFER_H
#include<iostream>
#include<cstring> #include<vector> #include<atomic>
#include<unistd.h> #include<sys/uio.h> #include<assert.h>
class Buffer { public: Buffer(int InitBufferSize = 1024); ~Buffer() = default; size_t WritableBytes() const; size_t ReadableBytes() const; size_t PrependableBytes() const;
const char* Peek() const; void EnsureWriteable(size_t len); void HasWritten(size_t len);
void Retrieve(size_t len); void RetrieveUntil(const char* end); void RetrieveAll(); std::string RetrieveAllToStr();
const char* BeginWriteConst() const; char * BeginWrite();
void Append(const std::string& str); void Append(const char* str, size_t len); void Append(const void* data, size_t len); void Append(const Buffer& buff);
ssize_t ReadFd(int fd, int* SaveErrno); ssize_t WriteFd(int fd, int* SaveErrno);
private: char* BeginPtr_(); const char* BeginPtr_() const; void MakeSpace_(size_t len);
std::vector<char> buffer_; std::atomic<std::size_t> readPos_; std::atomic<std::size_t> writePos_; };
#endif
|
buffer.c
在编写.cpp文件时:
大部分函数声明 =
Buffer+作用域符(::)
{
看buffer构造图写代码;
}
记得assert()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
| #include "buffer.h"
Buffer::Buffer(int InitBufferSize) : buffer_(InitBufferSize), readPos_(0), writePos_(0) {}
size_t Buffer::WritableBytes() const { return buffer_.size() - Buffer::writePos_; } size_t Buffer::ReadableBytes() const { return writePos_ - readPos_; } size_t Buffer::PrependableBytes() const { return readPos_; }
const char *Buffer::Peek() const { return BeginPtr_() + readPos_; }
void Buffer::EnsureWriteable(size_t len) { if (WritableBytes() < len) MakeSpace_(len); assert(WritableBytes() >= len); } void Buffer::HasWritten(size_t len) { writePos_ = writePos_ + len; }
void Buffer::Retrieve(size_t len) { assert(len <= ReadableBytes()); readPos_ = readPos_ + len; } void Buffer::RetrieveUntil(const char *end) { assert(Peek() <= end); Retrieve(end - Peek()); } void Buffer::RetrieveAll() { readPos_ = writePos_ = 0; }
std::string Buffer::RetrieveAllToStr() { std::string str(Peek(), ReadableBytes()); RetrieveAll(); return str; }
const char *Buffer::BeginWriteConst() const { return BeginPtr_() + writePos_; } char *Buffer::BeginWrite() { return BeginPtr_() + writePos_; }
void Buffer::Append(const std::string &str) { Append(str.data(), str.length()); }
void Buffer::Append(const char *str, size_t len) { assert(str); EnsureWriteable(len); std::copy(str, str + len, BeginWrite()); HasWritten(len); }
void Buffer::Append(const void *data, size_t len) { assert(data); Append(static_cast<const char *>(data), len); }
void Buffer::Append(const Buffer &buff) { Append(buff.Peek(), buff.ReadableBytes()); }
ssize_t Buffer::ReadFd(int fd, int *SaveErrno) { char buff[65535]; struct iovec iov[2]; const size_t writable = WritableBytes(); iov[0].iov_base = BeginPtr_() + writePos_; iov[0].iov_len = writable; iov[1].iov_base = &buff; iov[1].iov_len = sizeof(buff);
const ssize_t len = readv(fd, iov, 2); if (len <= 0) { *SaveErrno = errno; } else if (static_cast<size_t>(len) <= writable) { HasWritten(len); } else { writePos_ = buffer_.size(); Buffer::Append(buff, len - writable); } return len; }
ssize_t Buffer::WriteFd(int fd, int *SaveErrno) {
ssize_t len = write(fd, Peek(), ReadableBytes()); if (len <= 0) { *SaveErrno = errno; return len; } Retrieve(len); return len; }
char *Buffer::BeginPtr_() { return &*buffer_.begin(); } const char *Buffer::BeginPtr_() const { return &*buffer_.begin(); } void Buffer::MakeSpace_(size_t len) { if (WritableBytes() + PrependableBytes() < len) { buffer_.resize(writePos_ + len + 1); } else { size_t readable = ReadableBytes(); std::copy(Peek(), Peek() + readable, BeginPtr_()); readPos_ = 0; writePos_ = readPos_ + readable; assert(readable == ReadableBytes()); } }
|