提要
在讲解PhxRPC
的之前,介绍streambuf
是必要的,本篇会带大家走一遍 steambuf
继承重写流程,分别实现两套用缓冲区的流操作读入写出。
一个是文件的读入写出,一个是socket
网络数据的读入写出,他们之间的流操作方式会有差异,这个差异是用来提醒流操作和缓冲区半毛线关系都没有,当你实现了缓冲区。
如果不把它和流绑定到一起,那么很不幸,你就只能跟操作一个对象一样,调用streambuf
函数进行处理了。
这些实现总共用到如下几个streambuf
和流的函数:
setg() // 设置输入缓冲区
setp() // 设置输出缓冲区
pbase() // 输出缓冲区的起始地址
eback() // 输入缓冲区的起始地址
gptr() // 当前输入缓冲区数据指针
pptr() // 当前输出缓冲区数据指针
pbump() // 移动输出缓冲区的指针
gbump() // 移动输入缓冲区的指针
sputc() // 将一个字节写入输出缓冲区
sync() // 调用flush函数时会调用此函数,将输出缓冲区的数据写入目标对象,同时清空缓冲区
overflow() // 当输出缓冲区溢出时,调用此函数将输出缓冲区的数据写入目标对象中
underflow() // 当输入缓冲区空了时,调用此函数将数据源中的数据源读取到缓冲区缓冲区中
flush() // 调用sync函数
good() // 判断是否调用成功
FileStreamBuf.cc
文件
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <streambuf>
class FileBufferStreamBuf : public std::streambuf {
public:
FileBufferStreamBuf(FILE* fp, size_t buf_size, size_t put_back_size):
fp_(fp),
buf_size_(buf_size),
put_back_size_(put_back_size) {
char* gbuf = new char[buf_size_ + put_back_size_];
char* pbuf = new char[buf_size_];
// 此设计第一次调用时就会触发underflow函数,将数据读入缓冲区中
setg(gbuf, gbuf, gbuf); // 参数(输入缓冲区起始地址,输入缓冲区指针指向,输入缓冲区的结束地址)
setp(pbuf, pbuf + buf_size_); // 参数(输出缓冲区的起始地址,输出缓冲区的结束地址)
}
// 调用flush()函数刷新的时候会调用此函数
int sync() {
int sent = 0;
int total = pptr() - pbase();
while(sent < total) {
int ret = fwrite(pbase() + sent, 1, total - sent, fp_); // 写入文件操作
if (ret > 0) {
sent += ret;
} else {
return -1;
}
}
pbump(-total); // 移动缓冲区指针到起始位置
return 0;
}
// 当缓冲区溢出时,调用此函数将缓冲区的数据写入目标对象中
int overflow(int c) {
if (-1 == sync()) {
return EOF;
} else {
sputc(static_cast<char>(c));
return c;