創建buffer
在io操作中,對數據的讀寫大都是在一個緩沖區上進行的,在asio框架中,可以通過asio::buffer函數創建一個緩沖區來提供數據的讀寫。buffer函數本身並不申請內存,只是提供了一個對現有內存的封裝。
char d1[128];
size_t bytes_transferred = sock.receive(asio::buffer(d1));
直接用字符串做buffer也是常見的形式:
string str = " hello world " ;
size_t bytes_transferred = sock.send(asio::buffer(str));
除了這些基礎類型外,也可以使用stl中的容器,非常方便。
asio::buffer(std::vector<char>(128));
asio::buffer(std::array<char,128>());
將buffer還原為數據對象
前面的操作是通過把數據對象封裝成buffer,在使用過程中往往也需要把buffer還原為數據對象。
char* p1 = asio::buffer_cast<char*>(buffer);
獲取buffer大小
可以通過buffer_size函數獲取buffer大小。
size_t s1 = asio::buffer_size(buf);
讀寫buffer
讀寫buffer一般都是和io對象相關聯的,io對象成員函數中就提供了讀寫操作。以tcp::socket對象為例,它提供了read_some和write_some來實現讀寫操作:
std::array<char, 128> buf;
sock.read_some(asio::buffer(buf));
另外,asio名字空間下也提供了通用的read、write函數,通過它們可以實現更加高級的讀寫功能
size_t bytes_transfered = asio::read(sock, asio::buffer(buf), asio::transfer_all(), err);
這里我就使用了transfer_all標記強制讀滿buffer才返回,另外還有兩個比較常用的標記transfer_at_least()和transfer_exactly(),非常方便。
streambuf
asio::streambuf則是提供了一個流類型的buffer,它自身是能申請內存的。它的好處是可以通過stl的stream相關函數實現緩沖區操作,處理起來更加方便。
//通過streambuf發送數據
asio::streambuf b;
std::ostream os(&b);
os << "Hello, World!\n";
size_t n = sock.send(b.data()); // try sending some data in input sequence
b.consume(n); // sent data is removed from input sequence
//通過streambuf讀數據
asio::streambuf b;
asio::streambuf::mutable_buffers_type bufs = b.prepare(512); // reserve 512 bytes in output sequence
size_t n = sock.receive(bufs);
b.commit(n); // received data is "committed" from output sequence to input sequence
std::istream is(&b);
std::string s;
is >> s;
另外,asio名字空間下還提供了一個的read_until函數,可以實現讀到滿足指定條件的字符串為止,對於解析協議來說非常有用。
size_t n = asio::read_until(sock, stream, '\n');
asio::streambuf::const_buffers_type bufs = sb.data();
std::string line(asio::buffers_begin(bufs), asio::buffers_begin(bufs) + n);
這個指定條件除了是字符串外,還可以是正則表達式,非常給力。這也是asio庫為什么要依賴於boost.regex的原因。(雖然regex已經標准化了,但仍得使用boost.regex庫。等什么時候asio也標准化后估計就可以直接使用std.regex庫了)
自定義內存分配
異步IO操作時往往會申請動態內存,使用完后就釋放掉;在IO密集型的場景中,頻繁的申請釋放內存對性能會有較大影響。為了避免這個問題,asio提供了一個內存池式的模型 asio_handler_allocate 和 asio_handler_deallocate 來復用內存。
例子我就不寫了,可以參看boost官方文檔示例,或者網上的這篇文章。
就我個人而言,並不贊成在項目的前期就使用上這個allocator,畢竟這樣帶來了很大的代碼復雜度。而是作為一個性能優化點,在后期性能優化的時候再試試用它有沒有效果。並且內存池的也有很多不同的方案,google的google-perftools也值得一試。