c++實(shí)現(xiàn)一個(gè)簡(jiǎn)易的網(wǎng)絡(luò)緩沖區(qū)的實(shí)踐
1. 前言
請(qǐng)思考以下幾個(gè)問(wèn)題:
1).為什么需要設(shè)計(jì)網(wǎng)絡(luò)緩沖區(qū),內(nèi)核中不是有讀寫緩沖區(qū)嗎?
需要設(shè)計(jì)的網(wǎng)絡(luò)緩沖區(qū)和內(nèi)核中TCP緩沖區(qū)的關(guān)系如下圖所示,通過(guò)socket進(jìn)行進(jìn)行綁定。具體來(lái)說(shuō)網(wǎng)絡(luò)緩沖區(qū)包括讀(接收)緩沖區(qū)和寫(發(fā)送)緩沖區(qū)。設(shè)計(jì)讀緩沖區(qū)的目的是:當(dāng)從TCP中讀數(shù)據(jù)時(shí),不能確定讀到的是一個(gè)完整的數(shù)據(jù)包,如果是不完整的數(shù)據(jù)包,需要先放入緩沖區(qū)中進(jìn)行緩存,直到數(shù)據(jù)包完整才進(jìn)行業(yè)務(wù)處理。設(shè)計(jì)寫緩沖區(qū)的目的是:向TCP寫數(shù)據(jù)不能保證所有數(shù)據(jù)寫成功,如果TCP寫緩沖區(qū)已滿,則會(huì)丟棄數(shù)據(jù)包,所以需要一個(gè)寫緩沖區(qū)暫時(shí)存儲(chǔ)需要寫的數(shù)據(jù)。
2).緩沖區(qū)應(yīng)該設(shè)置為堆內(nèi)存還是棧內(nèi)存?
假設(shè)有一個(gè)服務(wù)端程序,需要同時(shí)連接多個(gè)客戶端,每一個(gè)socket就是一個(gè)連接對(duì)象,所以不同的socket都需要自己對(duì)應(yīng)的讀寫緩沖區(qū)。如果將緩沖區(qū)設(shè)置為棧內(nèi)存,很容易爆掉,故將將其設(shè)置為堆內(nèi)存更加合理。此外,緩沖區(qū)容量上限一般是有限制的,一開始不需要分配過(guò)大,僅僅在緩沖區(qū)不足時(shí)進(jìn)行擴(kuò)展。
3).讀寫緩沖區(qū)的基本要求是什么?
通過(guò)以上分析,不難得出讀寫緩沖區(qū)雖然是兩個(gè)獨(dú)立的緩沖區(qū),但是其核心功能相同,可以復(fù)用其代碼。
讀寫緩沖區(qū)至少提供兩類接口:存儲(chǔ)數(shù)據(jù)和讀取數(shù)據(jù)
讀寫緩沖區(qū)要求:先進(jìn)先出,保證存儲(chǔ)的數(shù)據(jù)是有序的
4).如何界定數(shù)據(jù)包?
第一種使用特殊字符界定數(shù)據(jù)包:例如\n
,\r\n
,第二種通過(guò)長(zhǎng)度界定數(shù)據(jù)包,數(shù)據(jù)包中首先存儲(chǔ)的是整個(gè)數(shù)據(jù)包的長(zhǎng)度,再根據(jù)長(zhǎng)度進(jìn)行讀取。
5).幾種常見的緩沖區(qū)設(shè)計(jì)
①ringbuffer+讀寫指針
ringbuffer是一段連續(xù)的內(nèi)存,當(dāng)末端已經(jīng)寫入數(shù)據(jù)后,會(huì)從頭部繼續(xù)寫數(shù)據(jù),所以感覺(jué)上像一個(gè)環(huán),實(shí)際是一個(gè)循環(huán)數(shù)組。ringbuffer的缺點(diǎn)也很明顯:不能夠擴(kuò)展、對(duì)于首尾部分的數(shù)據(jù)需要增加一次IO調(diào)用。
②可擴(kuò)展的讀寫緩沖區(qū)+讀寫指針
下圖設(shè)計(jì)了一種可擴(kuò)展的讀寫緩沖區(qū),在創(chuàng)建時(shí)會(huì)分配一塊固定大小的內(nèi)存,整個(gè)結(jié)構(gòu)分為預(yù)留空間數(shù)據(jù)空間。預(yù)留空間用于存儲(chǔ)必要的信息,真正存儲(chǔ)數(shù)據(jù)的空間由連續(xù)內(nèi)存組成。此種緩沖區(qū)設(shè)計(jì)相對(duì)于ringbuffer能夠擴(kuò)展,但是也有一定的缺點(diǎn):由于需要最大化利用空間,會(huì)將數(shù)據(jù)移動(dòng)至開頭,移動(dòng)操作會(huì)降低讀寫速度。
本文實(shí)現(xiàn)可擴(kuò)展的讀寫緩沖區(qū)+讀寫指針
2. 數(shù)據(jù)結(jié)構(gòu)
①Buffer類的設(shè)計(jì)與初始化
Buffer類的數(shù)據(jù)結(jié)構(gòu)如下所示,m_s
是指向緩沖區(qū)的指針,m_max_size
是緩沖區(qū)的長(zhǎng)度,初始設(shè)置為10,并根據(jù)擴(kuò)展因子m_expand_par
進(jìn)行倍增。擴(kuò)展因子m_expand_par
設(shè)置為2,表示每次擴(kuò)增長(zhǎng)度翻倍,也就是說(shuō)緩沖區(qū)的長(zhǎng)度隨擴(kuò)展依次為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ū)長(zhǎng)度 size_t m_expand_par; //擴(kuò)展因子 };
構(gòu)造函數(shù)的初始化列表中初始化成員變量。實(shí)際初始化緩沖區(qū)在init函數(shù)中分配內(nèi)存,大小為m_max_size
。不在構(gòu)造函數(shù)中初始化緩沖區(qū)的原因是:如果構(gòu)造函數(shù)中分配失敗,無(wú)法處理,也可使用RAII手段進(jìn)行處理
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; }
②讀寫指針的位置變化
當(dāng)緩沖區(qū)為空時(shí),讀寫指針位置相同都為0。
在寫入長(zhǎng)度為6的數(shù)據(jù)后,讀寫指針位置如圖
接著讀取兩個(gè)字節(jié)后,讀寫指針如圖
③擴(kuò)展緩沖區(qū)實(shí)現(xiàn)
擴(kuò)展緩沖區(qū)實(shí)際分為兩步,將有效數(shù)據(jù)前移至緩沖區(qū)頭(最大化利用數(shù)據(jù)),再進(jìn)行擴(kuò)展。根據(jù)成員變量擴(kuò)展因子m_expand_par
的值,將緩沖區(qū)按倍數(shù)擴(kuò)大。
假設(shè)當(dāng)前存儲(chǔ)數(shù)據(jù)4個(gè)字節(jié),讀寫指針如下圖。需要新增9個(gè)字節(jié)
將數(shù)據(jù)前移至緩沖區(qū)頭
擴(kuò)展緩沖區(qū)為2倍
寫入9個(gè)字節(jié)
實(shí)際需要實(shí)現(xiàn)的兩個(gè)私有成員函數(shù):調(diào)整數(shù)據(jù)位置至緩沖區(qū)頭adjust_buffer()
和擴(kuò)展expand_buffer()
,設(shè)置為私有屬性則是因?yàn)椴幌M脩粽{(diào)用,僅僅在寫入緩沖區(qū)前判斷不夠就進(jìn)行擴(kuò)展,用戶不應(yīng)該知道與主動(dòng)調(diào)用。
class Buffer { public: ... private: void adjust_buffer(); //調(diào)整數(shù)據(jù)位置至緩沖區(qū)頭部頭 void expand_buffer(size_t need_size); //擴(kuò)展緩沖區(qū)長(zhǎng)度 ... }
adjust_buffer()
實(shí)現(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 << "個(gè)字節(jié)" << endl; m_read_index = 0; //讀指針置0 } cout << "調(diào)整后read_index write_index" << m_read_index << " " << m_write_index << endl; }
擴(kuò)展緩沖區(qū)實(shí)現(xiàn)如下:
- 首先根據(jù)需要寫入的字節(jié)數(shù)判斷緩沖區(qū)長(zhǎng)度多大才能夠容下
- 申請(qǐng)新的存儲(chǔ)區(qū),并將數(shù)據(jù)拷貝到新存儲(chǔ)區(qū)
- 釋放舊緩沖區(qū),將新存儲(chǔ)區(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)存儲(chǔ)的字節(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) { //剩余空間不夠時(shí)擴(kuò)展,用while表示直到擴(kuò)展至夠用 expand_size *= m_expand_par; remain_size = expand_size - used_size; //cout << "擴(kuò)展長(zhǎng)度中... 總剩余 總長(zhǎng)度 " << remain_size << " " << expand_size << endl; } char* s1 = new char[expand_size](); //申請(qǐng)新的空間 memcpy(s1, m_s, m_max_size); free(m_s); m_s = s1; //將新空間掛載到緩沖區(qū) m_max_size = expand_size; //更新緩沖區(qū)總長(zhǎng)度 //cout << "擴(kuò)展結(jié)束,總長(zhǎng)度為" << m_max_size << endl; }
3. 外部接口設(shè)計(jì)與實(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(); //存儲(chǔ)數(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()
實(shí)現(xiàn)的思路如流程圖所示:
判斷剩余空間:
剩余空間不夠:調(diào)整數(shù)據(jù)至頭部、擴(kuò)展緩沖區(qū)
剩余空間足夠:向下繼續(xù)
判斷當(dāng)前空間:
當(dāng)前空間不夠:調(diào)整數(shù)據(jù)至頭部
剩余空間足夠:向下繼續(xù)
存儲(chǔ)數(shù)據(jù)
根據(jù)流程圖實(shí)現(xiàn)起來(lái)邏輯非常清晰,src表示原始數(shù)據(jù)
void Buffer::write_to_buffer(char* src) { size_t used_size = m_write_index - m_read_index; //used_size表示已經(jīng)存儲(chǔ)的字節(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表示當(dāng)前能夠存儲(chǔ)的空間 size_t size = init_random_write(&src); //printf("已經(jīng)使用%d,剩余總長(zhǎng)度%d,剩余當(dāng)前長(zhǎng)度%d\n", used_size, remain_size, cur_size); if (size > remain_size) { //剩余空間不夠 adjust_buffer(); expand_buffer(size); } else if (size > cur_size) { //剩余空間夠,當(dāng)前存不下 adjust_buffer(); } memcpy(&m_s[m_write_index], src, size); //存儲(chǔ)數(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,剩余總長(zhǎng)度%d,剩余當(dāng)前長(zhǎng)度%d\n", used_size, remain_size, cur_size); }
流程圖中還出現(xiàn)隨機(jī)一段數(shù)據(jù),這是用來(lái)調(diào)試的。隨機(jī)初始化一段長(zhǎng)度為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 << "準(zhǔn)備寫入的長(zhǎng)度為" << 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ù)返回實(shí)際讀取的字節(jié)數(shù)。實(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存儲(chǔ)的字節(jié)數(shù) if (read_size == 0 || read_max == 0) //讀取0字節(jié)和空緩存區(qū)時(shí)直接返回 return 0; if (read_size == -1) { //全讀走 memcpy(dst, &m_s[m_read_index], read_max); m_read_index += read_max; cout << "讀取了" << read_max << "個(gè)字節(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 << "個(gè)字節(jié)" << endl; } return read_size; //返回讀取的字節(jié)數(shù) }
③ 丟棄數(shù)據(jù)pop_bytes
size_t pop_bytes(size_t size)
傳入需要丟棄的字節(jié)數(shù),需要注意的是需要丟棄的字節(jié)數(shù)為-1
表示全部丟棄;-2表示隨機(jī)丟棄0~ 40字節(jié),函數(shù)返回實(shí)際丟棄的字節(jié)數(shù)。實(shí)現(xiàn)如流程圖所示:
size_t Buffer::pop_bytes(size_t size) { size_t read_max = m_write_index - m_read_index; //存儲(chǔ)數(shù)據(jù)長(zhǎng)度 //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 << "個(gè)字節(jié)" << endl; return read_max; } if (size > 0) { //丟棄指定字節(jié) if (size > read_max) size = read_max; m_read_index += size; cout << "丟棄了" << size << "個(gè)字節(jié)" << endl; } return size; }
④ 其他接口
peek_read()
和peek_write()
返回讀寫指針的位置
size_t peek_read(); //指向準(zhǔn)備讀的位置(調(diào)試用) size_t peek_write(); //指向準(zhǔn)備寫的位置(調(diào)試用) size_t Buffer::peek_write() { return m_write_index; } size_t Buffer::peek_read() { return m_read_index; }
4. 完整代碼與測(cè)試
① 完整代碼
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(); //得到存儲(chǔ)數(shù)據(jù)的字節(jié)數(shù) size_t peek_read(); //指向準(zhǔn)備讀的位置(調(diào)試用) size_t peek_write(); //指向準(zhǔn)備寫的位置(調(diào)試用) private: void adjust_buffer(); //調(diào)整數(shù)據(jù)位置至緩沖區(qū)頭 void expand_buffer(size_t need_size); //擴(kuò)展緩沖區(qū)長(zhǎng)度 size_t init_random_write(char** src); //隨機(jī)初始化一段數(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ū)長(zhǎng)度 size_t m_expand_par; //擴(kuò)展因子 };
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存儲(chǔ)的字節(jié)數(shù) if (read_size == 0 || read_max == 0) //讀取0字節(jié)和空緩存區(qū)時(shí)直接返回 return 0; if (read_size == -1) { //全讀走 memcpy(dst, &m_s[m_read_index], read_max); m_read_index += read_max; printf("讀取完成:\t讀取%d個(gè)字節(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個(gè)字節(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)存儲(chǔ)的字節(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表示當(dāng)前能夠存儲(chǔ)的空間 size_t size = init_random_write(&src); //printf("已經(jīng)使用%d,剩余總長(zhǎng)度%d,剩余當(dāng)前長(zhǎng)度%d\n", used_size, remain_size, cur_size); if (size > remain_size) { //剩余空間不夠 adjust_buffer(); expand_buffer(size); } else if (size > cur_size) { //剩余空間夠,當(dāng)前存不下 adjust_buffer(); } memcpy(&m_s[m_write_index], src, size); //存儲(chǔ)數(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總存儲(chǔ)%d,剩余空間%d,剩余當(dāng)前空間%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; //存儲(chǔ)數(shù)據(jù)長(zhǎng)度 //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 << "個(gè)字節(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 << "個(gè)字節(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 << "隨機(jī)寫入:\t長(zhǎng)度為" << 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 << "個(gè)字節(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)存儲(chǔ)的字節(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) { //剩余空間不夠時(shí)擴(kuò)展,用while表示直到擴(kuò)展至夠用 expand_size *= m_expand_par; remain_size = expand_size - used_size; cout << "擴(kuò)展長(zhǎng)度中... 總剩余 總長(zhǎng)度 " << remain_size << " " << expand_size << endl; } char* s1 = new char[expand_size](); //申請(qǐng)新的空間 memcpy(s1, m_s, m_max_size); free(m_s); m_s = s1; //將新空間掛載到緩沖區(qū) m_max_size = expand_size; //更新緩沖區(qū)總長(zhǎng)度 cout << "擴(kuò)展結(jié)束,總長(zhǎng)度為" << m_max_size << endl; }
② 測(cè)試
int main() { srand((unsigned)time(NULL)); //調(diào)試需要初始化隨機(jī)種子 Buffer* pbuffer = new Buffer(); //創(chuàng)建Buffer對(duì)象 if (pbuffer->init() != 0) //init函數(shù)分配緩沖區(qū) return 0; { char* s = nullptr; //s是指向隨機(jī)數(shù)據(jù)的指針 char* read = new char[1000]; //讀取時(shí)將數(shù)據(jù)存儲(chǔ)到的指針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ù)總寫入-總讀取和一共存儲(chǔ)的字節(jié)數(shù)判斷是否存儲(chǔ)正確 cout << "error!!!" << endl; } else cout << "test is ok\n\n\n"; } delete s; delete[] read; delete pbuffer; return 0; }
隨機(jī)1000000次測(cè)試
int main() { srand((unsigned)time(NULL)); //調(diào)試需要初始化隨機(jī)種子 Buffer* pbuffer = new Buffer(); //創(chuàng)建Buffer對(duì)象 if (pbuffer->init() != 0) //init函數(shù)分配緩沖區(qū) return 0; char* s = nullptr; //s是指向隨機(jī)數(shù)據(jù)的指針 char* read = new char[1000]; //讀取時(shí)將數(shù)據(jù)存儲(chǔ)到的指針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ù)總寫入-總讀取和一共存儲(chǔ)的字節(jié)數(shù)判斷是否存儲(chǔ)正確 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++實(shí)現(xiàn)一個(gè)簡(jiǎn)易的網(wǎng)絡(luò)緩沖區(qū)的實(shí)踐的文章就介紹到這了,更多相關(guān)c++ 網(wǎng)絡(luò)緩沖區(qū)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
c語(yǔ)言算術(shù)運(yùn)算符越界問(wèn)題解決方案
大量的安全漏洞是由于計(jì)算機(jī)算術(shù)運(yùn)算的微妙細(xì)節(jié)引起的, 具體的C語(yǔ)言, 諸如符號(hào)數(shù)和無(wú)符號(hào)數(shù)之間轉(zhuǎn)換, 算術(shù)運(yùn)算的越界都會(huì)導(dǎo)致不可預(yù)知的錯(cuò)誤和安全漏洞, 具體的案例數(shù)不勝數(shù).2012-11-11C++實(shí)現(xiàn)保存數(shù)據(jù)至EXCEL
這篇文章主要介紹了C++實(shí)現(xiàn)保存數(shù)據(jù)至EXCEL,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11C++中string與int的相互轉(zhuǎn)換實(shí)現(xiàn)代碼
這篇文章主要介紹了C++中string與int的相互轉(zhuǎn)換實(shí)現(xiàn)代碼,需要的朋友可以參考下2017-05-05String底層函數(shù)的實(shí)現(xiàn)方式詳解
這篇文章主要介紹了String底層函數(shù)的實(shí)現(xiàn)方式,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09數(shù)據(jù)結(jié)構(gòu)用兩個(gè)棧實(shí)現(xiàn)一個(gè)隊(duì)列的實(shí)例
這篇文章主要介紹了C++語(yǔ)言數(shù)據(jù)結(jié)構(gòu)用兩個(gè)棧實(shí)現(xiàn)一個(gè)隊(duì)列的實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-06-06c語(yǔ)言之char*和unsigned?char*的區(qū)別及說(shuō)明
這篇文章主要介紹了c語(yǔ)言之char*和unsigned?char*的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08詳解C語(yǔ)言結(jié)構(gòu)體中的函數(shù)指針
這篇文章主要介紹了詳解C語(yǔ)言結(jié)構(gòu)體中的函數(shù)指針,文中對(duì)函數(shù)指針的基本概念也有講解,需要的朋友可以參考下2016-04-04