c++實現(xiàn)一個簡易的網(wǎng)絡(luò)緩沖區(qū)的實踐
1. 前言
請思考以下幾個問題:
1).為什么需要設(shè)計網(wǎng)絡(luò)緩沖區(qū),內(nèi)核中不是有讀寫緩沖區(qū)嗎?
需要設(shè)計的網(wǎng)絡(luò)緩沖區(qū)和內(nèi)核中TCP緩沖區(qū)的關(guān)系如下圖所示,通過socket進行進行綁定。具體來說網(wǎng)絡(luò)緩沖區(qū)包括讀(接收)緩沖區(qū)和寫(發(fā)送)緩沖區(qū)。設(shè)計讀緩沖區(qū)的目的是:當從TCP中讀數(shù)據(jù)時,不能確定讀到的是一個完整的數(shù)據(jù)包,如果是不完整的數(shù)據(jù)包,需要先放入緩沖區(qū)中進行緩存,直到數(shù)據(jù)包完整才進行業(yè)務(wù)處理。設(shè)計寫緩沖區(qū)的目的是:向TCP寫數(shù)據(jù)不能保證所有數(shù)據(jù)寫成功,如果TCP寫緩沖區(qū)已滿,則會丟棄數(shù)據(jù)包,所以需要一個寫緩沖區(qū)暫時存儲需要寫的數(shù)據(jù)。

2).緩沖區(qū)應(yīng)該設(shè)置為堆內(nèi)存還是棧內(nèi)存?
假設(shè)有一個服務(wù)端程序,需要同時連接多個客戶端,每一個socket就是一個連接對象,所以不同的socket都需要自己對應(yīng)的讀寫緩沖區(qū)。如果將緩沖區(qū)設(shè)置為棧內(nèi)存,很容易爆掉,故將將其設(shè)置為堆內(nèi)存更加合理。此外,緩沖區(qū)容量上限一般是有限制的,一開始不需要分配過大,僅僅在緩沖區(qū)不足時進行擴展。

3).讀寫緩沖區(qū)的基本要求是什么?
通過以上分析,不難得出讀寫緩沖區(qū)雖然是兩個獨立的緩沖區(qū),但是其核心功能相同,可以復(fù)用其代碼。
讀寫緩沖區(qū)至少提供兩類接口:存儲數(shù)據(jù)和讀取數(shù)據(jù)
讀寫緩沖區(qū)要求:先進先出,保證存儲的數(shù)據(jù)是有序的
4).如何界定數(shù)據(jù)包?
第一種使用特殊字符界定數(shù)據(jù)包:例如\n,\r\n,第二種通過長度界定數(shù)據(jù)包,數(shù)據(jù)包中首先存儲的是整個數(shù)據(jù)包的長度,再根據(jù)長度進行讀取。
5).幾種常見的緩沖區(qū)設(shè)計
①ringbuffer+讀寫指針
ringbuffer是一段連續(xù)的內(nèi)存,當末端已經(jīng)寫入數(shù)據(jù)后,會從頭部繼續(xù)寫數(shù)據(jù),所以感覺上像一個環(huán),實際是一個循環(huán)數(shù)組。ringbuffer的缺點也很明顯:不能夠擴展、對于首尾部分的數(shù)據(jù)需要增加一次IO調(diào)用。

②可擴展的讀寫緩沖區(qū)+讀寫指針
下圖設(shè)計了一種可擴展的讀寫緩沖區(qū),在創(chuàng)建時會分配一塊固定大小的內(nèi)存,整個結(jié)構(gòu)分為預(yù)留空間數(shù)據(jù)空間。預(yù)留空間用于存儲必要的信息,真正存儲數(shù)據(jù)的空間由連續(xù)內(nèi)存組成。此種緩沖區(qū)設(shè)計相對于ringbuffer能夠擴展,但是也有一定的缺點:由于需要最大化利用空間,會將數(shù)據(jù)移動至開頭,移動操作會降低讀寫速度。
本文實現(xiàn)可擴展的讀寫緩沖區(qū)+讀寫指針

2. 數(shù)據(jù)結(jié)構(gòu)
①Buffer類的設(shè)計與初始化
Buffer類的數(shù)據(jù)結(jié)構(gòu)如下所示,m_s是指向緩沖區(qū)的指針,m_max_size是緩沖區(qū)的長度,初始設(shè)置為10,并根據(jù)擴展因子m_expand_par進行倍增。擴展因子m_expand_par設(shè)置為2,表示每次擴增長度翻倍,也就是說緩沖區(qū)的長度隨擴展依次為10、20、40、80。
class Buffer{
public:
Buffer(); //構(gòu)造
~Buffer();
int init(); //分配緩沖區(qū)
private:
char* m_s; //緩沖區(qū)指針
size_t m_read_index; //讀指針位置
size_t m_write_index; //寫指針位置
size_t m_max_size; //緩沖區(qū)長度
size_t m_expand_par; //擴展因子
};
構(gòu)造函數(shù)的初始化列表中初始化成員變量。實際初始化緩沖區(qū)在init函數(shù)中分配內(nèi)存,大小為m_max_size。不在構(gòu)造函數(shù)中初始化緩沖區(qū)的原因是:如果構(gòu)造函數(shù)中分配失敗,無法處理,也可使用RAII手段進行處理
Buffer::Buffer()
:m_read_index(0),m_write_index(0),m_max_size(10), m_expand_par(2),m_s(nullptr)
{}
Buffer::~Buffer()
{
delete[] m_s;
}
int Buffer::init()
{
m_s = new char[m_max_size]();
if (m_s == nullptr) {
cout << "分配m_s失敗\n";
return -1;
}
return 0;
}
②讀寫指針的位置變化
當緩沖區(qū)為空時,讀寫指針位置相同都為0。

在寫入長度為6的數(shù)據(jù)后,讀寫指針位置如圖

接著讀取兩個字節(jié)后,讀寫指針如圖

③擴展緩沖區(qū)實現(xiàn)
擴展緩沖區(qū)實際分為兩步,將有效數(shù)據(jù)前移至緩沖區(qū)頭(最大化利用數(shù)據(jù)),再進行擴展。根據(jù)成員變量擴展因子m_expand_par的值,將緩沖區(qū)按倍數(shù)擴大。
假設(shè)當前存儲數(shù)據(jù)4個字節(jié),讀寫指針如下圖。需要新增9個字節(jié)

將數(shù)據(jù)前移至緩沖區(qū)頭

擴展緩沖區(qū)為2倍

寫入9個字節(jié)

實際需要實現(xiàn)的兩個私有成員函數(shù):調(diào)整數(shù)據(jù)位置至緩沖區(qū)頭adjust_buffer()和擴展expand_buffer(),設(shè)置為私有屬性則是因為不希望用戶調(diào)用,僅僅在寫入緩沖區(qū)前判斷不夠就進行擴展,用戶不應(yīng)該知道與主動調(diào)用。
class Buffer {
public:
...
private:
void adjust_buffer(); //調(diào)整數(shù)據(jù)位置至緩沖區(qū)頭部頭
void expand_buffer(size_t need_size); //擴展緩沖區(qū)長度
...
}
adjust_buffer()實現(xiàn)如下,注釋寫的較為清楚,不再贅述
void Buffer::adjust_buffer()
{
if (m_read_index == 0) //數(shù)據(jù)已經(jīng)在頭部,直接返回
return;
int used_size = m_write_index - m_read_index;
if (used_size == 0) { //緩沖區(qū)為空,重置讀寫指針
m_write_index = 0;
m_read_index = 0;
}
else {
cout << "調(diào)整前read_index write_index" << m_read_index << " " << m_write_index << endl;
memcpy(m_s, &m_s[m_read_index], used_size); //將數(shù)據(jù)拷貝至頭部
m_write_index -= m_read_index; //寫指針也前移
cout << "調(diào)整了" << used_size << "個字節(jié)" << endl;
m_read_index = 0; //讀指針置0
}
cout << "調(diào)整后read_index write_index" << m_read_index << " " << m_write_index << endl;
}
擴展緩沖區(qū)實現(xiàn)如下:
- 首先根據(jù)需要寫入的字節(jié)數(shù)判斷緩沖區(qū)長度多大才能夠容下
- 申請新的存儲區(qū),并將數(shù)據(jù)拷貝到新存儲區(qū)
- 釋放舊緩沖區(qū),將新存儲區(qū)作為緩沖區(qū)
void Buffer::expand_buffer(size_t need_size) //need_size需要寫入的字節(jié)數(shù)
{
size_t used_size = m_write_index - m_read_index; //used_size表示已經(jīng)存儲的字節(jié)數(shù)
size_t remain_size = m_max_size - used_size; //remain_size表示剩余空間
size_t expand_size = m_max_size;
while (remain_size < need_size) { //剩余空間不夠時擴展,用while表示直到擴展至夠用
expand_size *= m_expand_par;
remain_size = expand_size - used_size;
//cout << "擴展長度中... 總剩余 總長度 " << remain_size << " " << expand_size << endl;
}
char* s1 = new char[expand_size](); //申請新的空間
memcpy(s1, m_s, m_max_size);
free(m_s);
m_s = s1; //將新空間掛載到緩沖區(qū)
m_max_size = expand_size; //更新緩沖區(qū)總長度
//cout << "擴展結(jié)束,總長度為" << m_max_size << endl;
}
3. 外部接口設(shè)計與實現(xiàn)
以讀緩沖區(qū)為例需要提供的接口有:向緩沖區(qū)寫入數(shù)據(jù)write_to_buffer(),向緩沖區(qū)讀取數(shù)據(jù)read_from_buffer(),得到能夠讀取的最大字節(jié)數(shù)readable_bytes()。
class Buffer {
public:
void write_to_buffer(char* src); //從src中寫數(shù)據(jù)
size_t readable_bytes(); //存儲數(shù)據(jù)的字節(jié)數(shù)
size_t read_from_buffer(char *dst,int bytes); //讀數(shù)據(jù)
size_t pop_bytes(size_t bytes); //丟棄數(shù)據(jù)
}
① 寫入緩沖區(qū)write_to_buffer()
write_to_buffer()實現(xiàn)的思路如流程圖所示:
判斷剩余空間:
剩余空間不夠:調(diào)整數(shù)據(jù)至頭部、擴展緩沖區(qū)
剩余空間足夠:向下繼續(xù)
判斷當前空間:
當前空間不夠:調(diào)整數(shù)據(jù)至頭部
剩余空間足夠:向下繼續(xù)
存儲數(shù)據(jù)

根據(jù)流程圖實現(xiàn)起來邏輯非常清晰,src表示原始數(shù)據(jù)
void Buffer::write_to_buffer(char* src)
{
size_t used_size = m_write_index - m_read_index; //used_size表示已經(jīng)存儲的字節(jié)數(shù)
size_t remain_size = m_max_size - used_size; //remain_size表示剩余空間
size_t cur_size = m_max_size - m_write_index; //cur_size表示當前能夠存儲的空間
size_t size = init_random_write(&src);
//printf("已經(jīng)使用%d,剩余總長度%d,剩余當前長度%d\n", used_size, remain_size, cur_size);
if (size > remain_size) { //剩余空間不夠
adjust_buffer();
expand_buffer(size);
}
else if (size > cur_size) { //剩余空間夠,當前存不下
adjust_buffer();
}
memcpy(&m_s[m_write_index], src, size); //存儲數(shù)據(jù)
m_write_index += size;
delete[] src;
//更新并打印log
//used_size = m_write_index - m_read_index;
//remain_size = m_max_size - used_size;
//cur_size = m_max_size - m_write_index;
//printf("已經(jīng)使用%d,剩余總長度%d,剩余當前長度%d\n", used_size, remain_size, cur_size);
}
流程圖中還出現(xiàn)隨機一段數(shù)據(jù),這是用來調(diào)試的。隨機初始化一段長度為0~ 40,字符a~ z的數(shù)據(jù),并寫緩存區(qū)
static int get_random_len() {
return rand() % 40;
}
static int get_random_ala() {
return rand() % 26;
}
size_t Buffer::init_random_write(char** src)
{
int size = get_random_len();
char ala = get_random_ala();
*src = new char[size];
cout << "準備寫入的長度為" << size << " 值全是 " << (unsigned char)('a' + ala) << endl;
for (int i = 0; i < size; i++) {
(*src)[i] = 'a' + ala;
}
return size;
}
② 讀取緩沖區(qū)read_from_buffer()
read_from_buffer(char*dst,int read_size)傳入需要拷貝到目的地址和需要讀取的字節(jié)數(shù),需要注意的是需要讀取的字節(jié)數(shù)為-1表示全部讀取,函數(shù)返回實際讀取的字節(jié)數(shù)。實現(xiàn)如流程圖所示:

代碼如下
size_t Buffer::read_from_buffer(char*dst,int read_size)
{
size_t read_max = m_write_index - m_read_index; //read_max存儲的字節(jié)數(shù)
if (read_size == 0 || read_max == 0) //讀取0字節(jié)和空緩存區(qū)時直接返回
return 0;
if (read_size == -1) { //全讀走
memcpy(dst, &m_s[m_read_index], read_max);
m_read_index += read_max;
cout << "讀取了" << read_max << "個字節(jié)" << endl;
}
else if (read_size > 0) { //讀取指定字節(jié)
if ((size_t)read_size > read_max)
read_size = read_max;
memcpy(dst, &m_s[m_read_index], read_size);
m_read_index += read_size;
cout << "讀取了" << read_size << "個字節(jié)" << endl;
}
return read_size; //返回讀取的字節(jié)數(shù)
}
③ 丟棄數(shù)據(jù)pop_bytes
size_t pop_bytes(size_t size)傳入需要丟棄的字節(jié)數(shù),需要注意的是需要丟棄的字節(jié)數(shù)為-1表示全部丟棄;-2表示隨機丟棄0~ 40字節(jié),函數(shù)返回實際丟棄的字節(jié)數(shù)。實現(xiàn)如流程圖所示:

size_t Buffer::pop_bytes(size_t size)
{
size_t read_max = m_write_index - m_read_index; //存儲數(shù)據(jù)長度
//test random
if (size == -2)
size = get_random_len();
if (size == 0 || read_max == 0) //緩沖區(qū)為空或丟棄0字節(jié)返回
return 0;
if (size == -1) { //全丟
m_read_index += read_max;
cout << "丟棄了" << read_max << "個字節(jié)" << endl;
return read_max;
}
if (size > 0) { //丟棄指定字節(jié)
if (size > read_max)
size = read_max;
m_read_index += size;
cout << "丟棄了" << size << "個字節(jié)" << endl;
}
return size;
}
④ 其他接口
peek_read()和peek_write()返回讀寫指針的位置
size_t peek_read(); //指向準備讀的位置(調(diào)試用)
size_t peek_write(); //指向準備寫的位置(調(diào)試用)
size_t Buffer::peek_write()
{
return m_write_index;
}
size_t Buffer::peek_read()
{
return m_read_index;
}
4. 完整代碼與測試
① 完整代碼
Buffer.h
#pragma once
class Buffer {
public:
Buffer(); //構(gòu)造
~Buffer(); //析構(gòu)
int init(); //分配緩沖區(qū)
void write_to_buffer(char* src); //寫數(shù)據(jù)
size_t pop_bytes(size_t bytes); //丟棄數(shù)據(jù)
size_t read_from_buffer(char *dst,int bytes);//讀數(shù)據(jù)
size_t readable_bytes(); //得到存儲數(shù)據(jù)的字節(jié)數(shù)
size_t peek_read(); //指向準備讀的位置(調(diào)試用)
size_t peek_write(); //指向準備寫的位置(調(diào)試用)
private:
void adjust_buffer(); //調(diào)整數(shù)據(jù)位置至緩沖區(qū)頭
void expand_buffer(size_t need_size); //擴展緩沖區(qū)長度
size_t init_random_write(char** src); //隨機初始化一段數(shù)據(jù)(調(diào)試用)
private:
char* m_s; //緩沖區(qū)指針
size_t m_read_index; //讀指針位置
size_t m_write_index; //寫指針位置
size_t m_max_size; //緩沖區(qū)長度
size_t m_expand_par; //擴展因子
};
Buffer.cpp:
#include "Buffer.h"
#include<iostream>
#include<time.h>
using namespace std;
int total_write = 0; //記錄總寫入
int total_read = 0; //記錄總讀取
static int get_random_len() {
return rand() % 40;
}
static int get_random_ala() {
return rand() % 26;
}
Buffer::Buffer()
:m_read_index(0),m_write_index(0),m_max_size(10), m_expand_par(2),m_s(nullptr)
{}
Buffer::~Buffer()
{
delete[] m_s;
}
int Buffer::init()
{
m_s = new char[m_max_size]();
if (m_s == nullptr) {
cout << "分配m_s失敗\n";
return -1;
}
return 0;
}
size_t Buffer::read_from_buffer(char*dst,int read_size)
{
size_t read_max = m_write_index - m_read_index; //read_max存儲的字節(jié)數(shù)
if (read_size == 0 || read_max == 0) //讀取0字節(jié)和空緩存區(qū)時直接返回
return 0;
if (read_size == -1) { //全讀走
memcpy(dst, &m_s[m_read_index], read_max);
m_read_index += read_max;
printf("讀取完成:\t讀取%d個字節(jié)\n", read_max);
total_read += read_max;
}
else if (read_size > 0) { //讀取指定字節(jié)
if ((size_t)read_size > read_max)
read_size = read_max;
memcpy(dst, &m_s[m_read_index], read_size);
m_read_index += read_size;
printf("讀取完成:\t讀取%d個字節(jié)\n", read_size);
total_read += read_size;
}
return read_size; //返回讀取的字節(jié)數(shù)
}
size_t Buffer::readable_bytes()
{
return m_write_index - m_read_index;
}
size_t Buffer::peek_write()
{
return m_write_index;
}
size_t Buffer::peek_read()
{
return m_read_index;
}
void Buffer::write_to_buffer(char* src)
{
size_t used_size = m_write_index - m_read_index; //used_size表示已經(jīng)存儲的字節(jié)數(shù)
size_t remain_size = m_max_size - used_size; //remain_size表示剩余空間
size_t cur_size = m_max_size - m_write_index; //cur_size表示當前能夠存儲的空間
size_t size = init_random_write(&src);
//printf("已經(jīng)使用%d,剩余總長度%d,剩余當前長度%d\n", used_size, remain_size, cur_size);
if (size > remain_size) { //剩余空間不夠
adjust_buffer();
expand_buffer(size);
}
else if (size > cur_size) { //剩余空間夠,當前存不下
adjust_buffer();
}
memcpy(&m_s[m_write_index], src, size); //存儲數(shù)據(jù)
m_write_index += size;
delete[] src;
//更新并打印log
used_size = m_write_index - m_read_index;
remain_size = m_max_size - used_size;
cur_size = m_max_size - m_write_index;
printf("寫入完成:\t總存儲%d,剩余空間%d,剩余當前空間%d\n", used_size, remain_size, cur_size);
}
size_t Buffer::pop_bytes(size_t size)
{
size_t read_max = m_write_index - m_read_index; //存儲數(shù)據(jù)長度
//test random
if (size == -2)
size = get_random_len();
if (size == 0 || read_max == 0) //緩沖區(qū)為空或丟棄0字節(jié)返回
return 0;
if (size == -1) { //全丟
m_read_index += read_max;
cout << "丟棄了" << read_max << "個字節(jié)" << endl;
total_read += read_max;
return read_max;
}
if (size > 0) { //丟棄指定字節(jié)
if (size > read_max)
size = read_max;
m_read_index += size;
cout << "丟棄了" << size << "個字節(jié)" << endl;
total_read += size;
}
return size;
}
size_t Buffer::init_random_write(char** src)
{
int size = get_random_len();
total_write += size;
*src = new char[size];
char ala = get_random_ala();
cout << "隨機寫入:\t長度為" << size << " 值全是 " << (unsigned char)('a' + ala) << endl;
for (int i = 0; i < size; i++) {
(*src)[i] = 'a' + ala;
}
return size;
}
void Buffer::adjust_buffer()
{
if (m_read_index == 0) //數(shù)據(jù)已經(jīng)在頭部,直接返回
return;
int used_size = m_write_index - m_read_index;
if (used_size == 0) { //緩沖區(qū)為空,重置讀寫指針
m_write_index = 0;
m_read_index = 0;
}
else {
cout << "調(diào)整前read_index write_index" << m_read_index << " " << m_write_index << endl;
memcpy(m_s, &m_s[m_read_index], used_size); //將數(shù)據(jù)拷貝至頭部
m_write_index -= m_read_index; //寫指針也前移
cout << "調(diào)整了" << used_size << "個字節(jié)" << endl;
m_read_index = 0; //讀指針置0
}
cout << "調(diào)整后read_index write_index" << m_read_index << " " << m_write_index << endl;
}
void Buffer::expand_buffer(size_t need_size) //need_size需要寫入的字節(jié)數(shù)
{
size_t used_size = m_write_index - m_read_index; //used_size表示已經(jīng)存儲的字節(jié)數(shù)
size_t remain_size = m_max_size - used_size; //remain_size表示剩余空間
size_t expand_size = m_max_size;
while (remain_size < need_size) { //剩余空間不夠時擴展,用while表示直到擴展至夠用
expand_size *= m_expand_par;
remain_size = expand_size - used_size;
cout << "擴展長度中... 總剩余 總長度 " << remain_size << " " << expand_size << endl;
}
char* s1 = new char[expand_size](); //申請新的空間
memcpy(s1, m_s, m_max_size);
free(m_s);
m_s = s1; //將新空間掛載到緩沖區(qū)
m_max_size = expand_size; //更新緩沖區(qū)總長度
cout << "擴展結(jié)束,總長度為" << m_max_size << endl;
}
② 測試
int main() {
srand((unsigned)time(NULL)); //調(diào)試需要初始化隨機種子
Buffer* pbuffer = new Buffer(); //創(chuàng)建Buffer對象
if (pbuffer->init() != 0) //init函數(shù)分配緩沖區(qū)
return 0;
{
char* s = nullptr; //s是指向隨機數(shù)據(jù)的指針
char* read = new char[1000]; //讀取時將數(shù)據(jù)存儲到的指針read
size_t read_size = 0; //本次讀取到的字節(jié)數(shù)
pbuffer->write_to_buffer(s);
read_size = pbuffer-> read_from_buffer(read, -1);
pbuffer->write_to_buffer(s);
pbuffer->pop_bytes(-2);
read_size = read_size = pbuffer-> read_from_buffer(read, 0);
pbuffer->write_to_buffer(s);
cout << "總寫入\t" << total_write << endl;;
cout << "總讀取\t" << total_read << endl;
cout << "目前寫入" << total_write - total_read << endl;
cout << "可讀取\t" << pbuffer->readable_bytes()<< endl;
printf(" write %d read %d \n", pbuffer->peek_write(),pbuffer->peek_read());
if (total_write - total_read != pbuffer->readable_bytes()) { //根據(jù)總寫入-總讀取和一共存儲的字節(jié)數(shù)判斷是否存儲正確
cout << "error!!!" << endl;
}
else
cout << "test is ok\n\n\n";
}
delete s;
delete[] read;
delete pbuffer;
return 0;
}
隨機1000000次測試
int main() {
srand((unsigned)time(NULL)); //調(diào)試需要初始化隨機種子
Buffer* pbuffer = new Buffer(); //創(chuàng)建Buffer對象
if (pbuffer->init() != 0) //init函數(shù)分配緩沖區(qū)
return 0;
char* s = nullptr; //s是指向隨機數(shù)據(jù)的指針
char* read = new char[1000]; //讀取時將數(shù)據(jù)存儲到的指針read
size_t read_size = 0; //本次讀取到的字節(jié)數(shù)
unsigned long long time = 0; //調(diào)試的循環(huán)次數(shù)
while (1) {
pbuffer->write_to_buffer(s);
read_size = pbuffer-> read_from_buffer(read, -1);
pbuffer->write_to_buffer(s);
pbuffer->write_to_buffer(s);
pbuffer->pop_bytes(-2);
read_size = read_size = pbuffer-> read_from_buffer(read, 0);
pbuffer->write_to_buffer(s);
pbuffer->pop_bytes(-2);
pbuffer->write_to_buffer(s);
read_size = pbuffer-> read_from_buffer(read, -1);
pbuffer->write_to_buffer(s);
pbuffer->write_to_buffer(s);
read_size = pbuffer-> read_from_buffer(read, 22);
pbuffer->write_to_buffer(s);
pbuffer->write_to_buffer(s);
read_size = pbuffer-> read_from_buffer(read, -1);
pbuffer->pop_bytes(-2);
pbuffer->pop_bytes(-2);
pbuffer->write_to_buffer(s);
pbuffer->write_to_buffer(s);
read_size = pbuffer-> read_from_buffer(read, 2);
pbuffer->write_to_buffer(s);
read_size = pbuffer-> read_from_buffer(read, 17);
pbuffer->write_to_buffer(s);
pbuffer->pop_bytes(-2);
pbuffer->write_to_buffer(s);
pbuffer->write_to_buffer(s);
pbuffer->read_from_buffer(read, 18);
cout << "總寫入\t" << total_write << endl;;
cout << "總讀取\t" << total_read << endl;
cout << "目前寫入" << total_write - total_read << endl;
cout << "可讀取\t" << pbuffer->readable_bytes()<< endl;
printf(" write %d read %d \n", pbuffer->peek_write(),pbuffer->peek_read());
if (total_write - total_read != pbuffer->readable_bytes()) { //根據(jù)總寫入-總讀取和一共存儲的字節(jié)數(shù)判斷是否存儲正確
cout << "error!!!" << endl;
break;
}
if (time == 1000000) //循環(huán)1000000次
{
cout << "1000000 ok!!!" << endl;
break;
}
cout << time++ << " is ok\n\n\n";
}
delete s;
delete[] read;
delete pbuffer;
return 0;
}
到此這篇關(guān)于c++實現(xiàn)一個簡易的網(wǎng)絡(luò)緩沖區(qū)的實踐的文章就介紹到這了,更多相關(guān)c++ 網(wǎng)絡(luò)緩沖區(qū)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
記一次ADL導(dǎo)致的C++代碼編譯錯誤的原因及解決方法
文章分析C++ ADL機制導(dǎo)致的print函數(shù)沖突,因<iostream>間接包含<print>頭文件,建議重命名或使用限定名稱解決,并強調(diào)IDE提示減少冗余頭文件以避免編譯問題,感興趣的朋友一起看看吧2025-07-07
C++ vector在多線程操作中出現(xiàn)內(nèi)存錯誤問題及解決
這篇文章主要介紹了C++ vector在多線程操作中出現(xiàn)內(nèi)存錯誤問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08
深入理解C++中public、protected及private用法
這篇文章主要介紹了C++中public、protected及private用法,對于C++面向?qū)ο蟪绦蛟O(shè)計來說是非常重要的概念,需要的朋友可以參考下2014-08-08

