您的位置:首页 > Web前端

【boost】boost::asio(4)——buffer用法

2017-10-24 15:03 876 查看
1.创建buffer

在io操作中,对数据的读写大都是在一个缓冲区上进行的,在asio框架中,可以通过asio::buffer函数创建一个缓冲区来提供数据的读写。buffer函数本身并不申请内存,只是提供了一个对现有内存的封装,大小是自动管理的。

(1)字符数组

[cpp] view
plain copy

char d1[128];  

size_t bytes_transferred = socket.receive(boost::asio::buffer(d1));  

(2)字符向量

[cpp] view
plain copy

std::vector<char> d2(128);  

size_t bytes_transferred = socket.receive(boost::asio::buffer(d2));  

(3)boost的数组

[cpp] view
plain copy

boost::array<char, 128> d3;  

size_t bytes_transferred = sock.receive(boost::asio::buffer(d3));   

(4)字符串

[cpp] view
plain copy

string str = "hello world";  

bytes_transferred = socket.send(boost::asio::buffer(str));   

2.将buffer还原为数据对象
前面的操作是通过把数据对象封装成buffer,在使用过程中往往也需要把buffer还原为数据对象。

[cpp] view
plain copy

char* p1 = boost::asio::buffer_cast<char*>(buffer);  

3.获取buffer大小

可以通过buffer_size函数获取buffer大小。

[cpp] view
plain copy

size_t s1 = boost::asio::buffer_size(buf);  

4.读写buffer

(1)由IO对象提供读写操作函数

读写buffer一般都是和io对象相关联的,io对象成员函数中就提供了读写操作。以tcp::socket对象为例,它提供了read_some和write_some来实现读写操作:

[cpp] view
plain copy

std::array<char, 128> buf;  

sock.read_some(boost::asio::buffer(buf));  

(2)asio命名空间下提供的read、write函数

asio名字空间下也提供了通用的read、write函数,通过它们可以实现更加高级的读写功能

[cpp] view
plain copy

boost::array<char, 128> buf;  

boost::system::error_code ec;  

std::size_t n = boost::asio::read(  

    socket,  

    boost::asio::buffer(buf),  

    boost::asio::transfer_all(),  

    ec);  

if (ec)  

{  

  // An error occurred.  

}  

else  

{  

  // n == 128  

}  

boost::asio::transfer_all()能够使buffer中的所有数据都传送完毕,即读满buffer为止。另外还有两个比较常用的标记transfer_at_least()和transfer_exactly(),非常方便。

[cpp] view
plain copy

std::size_t n = boost::asio::read(  

    socket,  

    boost::asio::buffer(buf),  

    boost::asio::transfer_at_least(64),  

    ec);  

意义即读满64字节为止。返回。

transfer_exactly()的例子略。

5.streambuf

asio::streambuf则是提供了一个流类型的buffer,它自身是能申请内存的。它的好处是可以通过stl的stream相关函数实现缓冲区操作,处理起来更加方便。

[cpp] view
plain copy

//通过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函数,可以实现读到满足指定条件的字符串为止,对于解析协议来说非常有用。

[cpp] view
plain copy

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库了)

6.自定义内存分配

异步IO操作时往往会申请动态内存,使用完后就释放掉;在IO密集型的场景中,频繁的申请释放内存对性能会有较大影响。为了避免这个问题,asio提供了一个内存池式的模型asio_handler_allocate 和 asio_handler_deallocate 来复用内存。

例子可以参看boost官方文档示例

内存池的也有很多不同的方案,google的google-perftools也值得一试。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  asio boost