文章目錄
- 1、關于buffer數據結構
- 1.1、簡單概括一下,我們可以用buffer() 函數生成我們要用的緩存存儲數據。
- 1.2、但是這太復雜了,可以直接用buffer函數轉化為send需要的參數類型:
- 1.3、output_buf可以直接傳遞給該send接口。我們也可以將數組轉化為send接受的類型
- 1.4、對于流式操作,我們可以用streambuf,將輸入輸出流和streambuf綁定,可以實現流式輸入和輸出
1、關于buffer數據結構
任何網絡庫都有提供buffer的數據結構,所謂buffer就是接收和發送數據時緩存數據的結構。
boost::asio提供了asio::mutable_buffer 和 asio::const_buffer這兩個結構,他們是一段連續的空間,首字節存儲了后續數據的長度。
asio::mutable_buffer用于寫服務,asio::const_buffer用于讀服務。但是這兩個結構都沒有被asio的api直接使用。
對于api的buffer參數,asio提出了MutableBufferSequence和ConstBufferSequence概念,他們是由多個asio::mutable_buffer和asio::const_buffer組成的。也就是說boost::asio為了節省空間,將一部分連續的空間組合起來,作為參數交給api使用。
我們可以理解為MutableBufferSequence的數據結構為std::vector<asio::mutable_buffer>。
結構如下:
每隔vector存儲的都是mutable_buffer的地址,每個mutable_buffer的第一個字節表示數據的長度,后面跟著數據內容。
這么復雜的結構交給用戶使用并不合適,所以asio提出了buffer()函數,該函數接收多種形式的字節流,該函數返回asio::mutable_buffers_1 或者asio::const_buffers_1結構的對象。
如果傳遞給buffer()的參數是一個只讀類型,則函數返回asio::const_buffers_1 類型對象。
如果傳遞給buffer()的參數是一個可寫類型,則返回asio::mutable_buffers_1 類型對象。
asio::const_buffers_1和asio::mutable_buffers_1是asio::mutable_buffer和asio::const_buffer的適配器,提供了符合MutableBufferSequence和ConstBufferSequence概念的接口,所以他們可以作為boost::asio的api函數的參數使用。
1.1、簡單概括一下,我們可以用buffer() 函數生成我們要用的緩存存儲數據。
比如boost的發送接口send要求的參數為ConstBufferSequence類型:
template<typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence & buffers);
我們需要將 “Hello World” 類型轉換為該類型。
void BoostAsio::UseConstBuffer(std::string& buffer) {boost::asio::const_buffer asio_buff(buffer.c_str(), buffer.length());std::vector<boost::asio::const_buffer> buffer_sequence;buffer_sequence.emplace_back(asio_buff);
}
這段代碼使用了C++編程語言和Boost.Asio庫來處理網絡和異步I/O操作。代碼主要功能是從一個std::string對象創建一個Boost.Asio的const_buffer,然后將這個const_buffer添加到一個const_buffer對象的向量中,通常在需要使用Boost.Asio進行網絡數據傳輸時會這樣做。
-
UseConstBuffer函數:UseConstBuffer函數以一個引用參數buffer作為輸入。函數的目的是創建一個const_buffer,然后將其添加到一個const_buffer對象的向量中。
-
創建const_buffer:代碼使用buffer.c_str()(字符串c風格表示)和buffer.length()(字符串長度)作為參數,創建了一個名為asio_buff的const_buffer。const_buffer表示一個常量數據的緩沖區,用于讀取操作。
-
準備緩沖區序列:創建一個名為buffer_sequence的std::vector,用于存儲boost::asio::const_buffer的實例。emplace_back函數將asio_buff添加到buffer_sequence中。
-
到此為止,buffer_sequence中會包含一個代表輸入std::string的const_buffer。
-
然而,有一個重要的方面需要考慮:buffer_sequence的作用域。目前,buffer_sequence是在UseConstBuffer函數內部定義的局部變量。如果你希望在函數外部使用buffer_sequence,你需要通過返回值或通過引用參數將其傳遞出來。
-
另外,請確保在代碼的其他部分使用了buffer_sequence來進行實際的網絡操作,例如使用Boost.Asio函數將數據發送到網絡套接字上。
-
最后,記得正確處理buffer參數引用的std::string對象的生命周期。由于const_buffer引用了字符串的底層字符數據,確保在使用緩沖區期間字符串保持有效。
emplace_back()和push_back()的區別:
在你的代碼中,使用了emplace_back()函數來將asio_buff添加到buffer_sequence中。emplace_back()是C++標準庫中std::vector的一個函數,用于在容器的末尾構造一個新元素。
與之相比,push_back()函數是另一個向std::vector中添加元素的函數,但它要求你傳遞一個已構造的元素(對象)。這意味著如果你使用push_back(),你需要首先創建一個const_buffer對象,然后將其傳遞給函數。而使用emplace_back(),你可以直接在容器中構造新元素,而不需要提前創建對象。
總的來說,emplace_back()通常會比 push_back() 更高效,因為它可以避免額外的對象構造和拷貝操作。在你的代碼中,使用emplace_back()來添加asio_buff是一個不錯的選擇,因為它允許直接在容器中構造const_buffer對象。
-
對象構造次數:
- push_back()接受一個已經構造好的對象,并將其副本添加到容器中。這意味著對象需要在調用push_back()之前構造好,然后在添加到容器時還需要執行拷貝構造或移動構造操作。
- emplace_back()在容器內部直接構造對象,避免了先構造然后拷貝或移動的步驟。它會將傳遞的參數直接用于對象的構造。
-
拷貝和移動操作:
- 在使用push_back()時,如果添加的對象是已經構造好的,就需要執行一次拷貝構造(如果容器中的對象類型支持拷貝構造)或移動構造(如果支持移動構造)操作,將對象的副本添加到容器中。
- 使用emplace_back()時,對象會直接在容器內部構造,避免了拷貝和移動操作。
-
內存分配:
- 當使用push_back()添加對象時,它首先會分配內存用于存儲對象的副本,然后執行拷貝或移動操作,最后調整容器的大小。這可能涉及到多次內存分配和釋放。
- 使用emplace_back()時,它直接在容器內構造對象,避免了額外的內存分配和釋放。
- 總之,emplace_back()通常更高效,因為它在容器內部直接構造對象,避免了額外的拷貝和移動操作,以及不必要的內存分配和釋放。這使得在需要向容器添加構造對象的情況下,emplace_back()更為優越。
1.2、但是這太復雜了,可以直接用buffer函數轉化為send需要的參數類型:
void BoostAsio::UseConstBuffer1(std::string& buffer) {boost::asio::const_buffers_1 out_buffer(boost::asio::buffer(buffer));
}
代碼段中使用了Boost.Asio庫來創建一個const_buffers_1對象,并通過boost::asio::buffer(buffer)將std::string轉換為用于網絡傳輸的緩沖區。讓我對這段代碼進行解釋:
-
函數名稱和參數:
- 這個函數名是UseConstBuffer1,它接受一個std::string&類型的參數buffer,傳入的字符串是要被發送的數據。
-
創建const_buffers_1對象:
- const_buffers_1是Boost.Asio庫中的一個類,用于包裝一個常量緩沖區,以便進行異步I/O操作。
- 通過boost::asio::buffer(buffer),將buffer(std::string)轉換為一個Boost.Asio緩沖區對象。
在代碼中,盡管你創建了一個const_buffers_1對象,但是這個對象在函數結束后會被銷毀,所以你需要在代碼中繼續使用這個對象進行實際的網絡操作,例如發送數據到套接字。
1.3、output_buf可以直接傳遞給該send接口。我們也可以將數組轉化為send接受的類型
void BoostAsio::UseBufferArray() {const size_t buf_size = 30;std::unique_ptr<char[]> buf(new char[buf_size]);auto input_buf = boost::asio::buffer(static_cast<void*>(buf.get()), buf_size);
}
這段代碼執行以下操作:
-
定義緩沖區大小:
- buf_size 是一個常量,表示緩沖區的大小,這里設置為 30 字節。
-
創建緩沖區數組:
- 使用 std::unique_ptr 創建了一個 char 數組,大小為 buf_size。
- std::unique_ptr<char[]> 是一個智能指針,用于管理動態分配的 char 數組。這樣做可以在結束作用域時自動釋放內存。
-
創建輸入緩沖區:
- 使用 boost::asio::buffer 函數創建了一個輸入緩沖區。
- buffer 函數的第一個參數是一個 void* 指針,它指向數據的起始地址。在這里,使用 buf.get() 獲取 std::unique_ptr 所管理的原始指針。
- 第二個參數是緩沖區的大小,即 buf_size。
總之,這段代碼的目的是創建一個大小為 30 字節的輸入緩沖區,其中使用了 std::unique_ptr 來管理動態分配的內存。這個緩沖區可以在異步 I/O 操作中使用,比如異步讀取數據到這個緩沖區中。記得在實際應用中,你需要使用 boost::asio::io_context 和套接字等組件來實現具體的異步 I/O 操作。
1.4、對于流式操作,我們可以用streambuf,將輸入輸出流和streambuf綁定,可以實現流式輸入和輸出
id use_stream_buffer() {asio::streambuf buf;std::ostream output(&buf);// Writing the message to the stream-based buffer.output << "Message1\nMessage2";// Now we want to read all data from a streambuf// until '\n' delimiter.// Instantiate an input stream which uses our // stream buffer.std::istream input(&buf);// We'll read data into this string.std::string message1;std::getline(input, message1);// Now message1 string contains 'Message1'.
}