一、buffer模块: 缓冲区模块
Buffer模块是一个缓冲区模块,用于实现通信中用户态的接收缓冲区和发送缓冲区功能。
二、提供的功能
存储数据,取出数据
三、实现思想
1.实现换出去得有一块内存空间,采用vector ,vector底层是一个线性的内存空间!
(一)要素
1.默认空间大小
2.当前的读取数据位置!
3.当前的写入数据位置!
(二)操作
- 写入位置
当前写入位置指向哪里,从哪里开始写入
如果后续剩余空间不够了! - 考虑整体缓冲区空闲空间是否足够!(因为读位置也会向后偏移,前后有可能有空闲空间)
足够:将数据移动到起始位置
不够:扩容,从当前写位置开始扩容足够大小!
数据一旦写入成功,当前写位置,向后偏移! - 读取数据
当前的读取位置指向哪里,就从哪里开始读取,前提是有数据可读
可读数据大小:当前写入位置,减去当前读取位置!
(三)框架设计
class buffer {
private:
std::vector<char> _buffer;
// 位置是一个相对偏移量,而不是绝对地址!
uint64_t _read_idx; // 读位置
uint64_t _write_idx; // 写位置
public:
1. 获取当前写的位置
2. 确保可写空间足够
3. 获取前沿空间大小
4. 获取后沿空间大小
5. 将写入据位置向后移动指定长度
6. 获取当前读取位置的地址!
7. 获取可读空间大小
8. 将读位置向后移动指定长度!
9. clear
四、实现代码
#include <ctime>
#include <cstring>
#include <iostream>
#include <vector>
#include <cassert>
#include <string>
using namespace std;
#define BUFFER_SIZE 1024
class Buffer {
private:
std::vector<char> _buffer; // 使用vector进行内存空间管理
uint64_t _read_idx; // 读偏移
uint64_t _write_idx; // 写偏移
public:
Buffer():_read_idx(0),_write_idx(0),_buffer(BUFFER_SIZE) {}
char* begin() {return &*_buffer.begin();}
// 获取当前写入起始地址
char *writePosition() { return begin() + _write_idx;}
// 获取当前读取起始地址
char *readPosition() { return begin() + _read_idx; }
// 获取缓冲区末尾空间大小 —— 写偏移之后的空闲空间,总体大小减去写偏移
uint64_t tailIdleSize() {return _buffer.size() - _write_idx; }
// 获取缓冲区起始空间大小 —— 读偏移之前的空闲空间
uint64_t handIdleSize() {return _read_idx ;}
// 获取可读空间大小 = 写偏移 - 读偏移
uint64_t readAbleSize() {return _write_idx - _read_idx ;}
// 将读偏移向后移动
void moveReadOffset(uint64_t len) {
// 向后移动大小必须小于可读数据大小
assert(len <= readAbleSize());
_read_idx += len;
}
// 将写偏移向后移动
void moveWriteOffset(uint64_t len) {
assert(len <= tailIdleSize());
_write_idx += len;
}
void ensureWriteSpace(uint64_t len) {
// 确保可写空间足够 (整体空间够了就移动数据,否则就扩容!)
if (tailIdleSize() >= len) return;
// 不够的话 ,判断加上起始位置够不够,够了将数据移动到起始位置
if (len <= tailIdleSize() + handIdleSize()) {
uint64_t rsz = readAbleSize(); //帮当前数据大小先保存起来
std::copy(readPosition(),readPosition() + rsz,begin()); // 把可读数据拷贝到起始位置
_read_idx = 0; // 读归为0
_write_idx = rsz; // 可读数据大小是写的偏移量!
}
else { // 总体空间不够!需要扩容,不移动数据,直接给写偏移之后扩容足够空间即可!
_buffer.resize(_write_idx + len);
}
}
// 写入数据
void Write(const void *data,uint64_t len) {
ensureWriteSpace(len);
const char *d = (const char*) data;
std::copy(d,d + len,writePosition());
}
void WriteAndPush(void* data,uint64_t len) {
Write(data,len);
moveWriteOffset(len);
}
void WriteStringAndPush(const std::string &data) {
writeString(data);
moveWriteOffset(data.size());
}
void writeString(const std::string &data) {
return Write(data.c_str(),data.size());
}
void writeBuffer(Buffer &data) {
return Write(data.readPosition(),data.readAbleSize());
}
void writeBufferAndPush(Buffer &data) {
writeBuffer(data);
moveWriteOffset(data.readAbleSize());
}
std::string readAsString (uint64_t len) {
assert(len <= readAbleSize());
std::string str;
str.resize(len);
Read(&str[0],len);
return str;
}
void Read(void *buf,uint64_t len) {
// 读取数据 1. 保证足够的空间 2.拷贝数据进去
// 要求获取的大小必须小于可读数据大小!
assert(len <= readAbleSize());
std::copy(readPosition(),readPosition() + len,(char*)buf);
}
void readAndPop(void *buf,uint64_t len) {
Read(buf,len);
moveReadOffset(len);
}
// 逐步调试!!!!!
std::string ReadAsStringAndPop(uint64_t len) {
assert(len <= readAbleSize());
std::string str = readAsString(len);
moveReadOffset(len);
return str;
}
char* FindCRLF() {
char *res = (char*)memchr(readPosition(),'\n',readAbleSize());
return res;
}
// 通常获取一行数据,这种情况针对是:
std::string getLine() {
char* pos = FindCRLF();
if (pos == NULL) {
return "";
}
// +1 为了把换行数据取出来!
return readAsString(pos - readPosition() + 1);
}
std::string getLineAndPop() {
std::string str = getLine();
moveReadOffset(str.size());
return str;
}
void Clear() { // 清空缓冲区!clear
// 只需要将偏移量归0即可!
_read_idx = 0;
_write_idx = 0;
}
};
五、进行测试
#include "server.hpp"
using namespace std;
// 控制打印信息!!!
#define INF 0
#define DBG 1
#define ERR 2
#define LOG_LEVEL INF
#define LOG(level,format,...) do{\
if (level < LOG_LEVEL) break;\
time_t t = time(NULL);\
struct tm *ltm = localtime(&t);\
char tmp[23] = {0};\
strftime(tmp,31,"%H:%M:%S",ltm);\
fprintf(stdout,"[%s,%s:%d] " format "\n",tmp,__FILE__,__LINE__,##__VA_ARGS__);\
}while(0)
#define INF_LOG(format, ...) LOG(INF, format, ##__VA_ARGS__)
#define DBG_LOG(format, ...) LOG(DBG, format, ##__VA_ARGS__)
#define ERR_LOG(format, ...) LOG(ERR, format, ##__VA_ARGS__)
int main() {
Buffer buf;
std::string str = "hello!";
// buf.WriteStringAndPush(str);
// Buffer buf1;
// buf1.writeBufferAndPush(buf);
// std::string tmp;
// tmp = buf1.ReadAsStringAndPop(buf.readAbleSize());
// cout << tmp << endl;
// cout << buf.readAbleSize() << endl;
// cout << buf1.readAbleSize() << endl;
for (int i = 0; i < 300; i ++) {
std::string str = "hello" + std::to_string(i) + '\n';
buf.WriteStringAndPush(str);
}
while(buf.readAbleSize() > 0) {
string line = buf.getLineAndPop();
LOG("hello");
}
// string tmp;
// tmp = buf.ReadAsStringAndPop(buf.readAbleSize());
// cout << tmp << endl;
return 0;
}
中秋快乐!