asio::streambuf的使用

这个神器设计的非常巧妙,它有两个流缓冲区。一个input序列,一个output序列。比较难理解的是,在streambuf内部看来,它需要读取output序列,写入input序列,这一点不符合直觉。但是考虑到在streambuf的外部用户看来,他们是从input序列读取数据,向output序列写入数据。这些外部用户包括: std::istream,std::ostream,socket类等等。streambuf的模型,可以理解为一个pipe,如下图所示:

基本用法:

int main()
{
    boost::asio::streambuf sb ;
    std::ostream os(&sb);
    os << "hello world!"; //steambuf会自动把数据转移到input sequence
    
    std::istream is(&sb);
    std::string s;
    is >> s;
    
    std::cout << s;
}

data()函数,直接拿到input_sequence去操作

int main()
{
    boost::asio::streambuf sb ;
        
    std::ostream os(&sb);
    os << "1234567890";
    
    
    auto input_sequence = sb.data();
    std::string str(boost::asio::buffers_begin(input_sequence),
                    boost::asio::buffers_begin(input_sequence) + 10);
    std::cout << "str = " << str << std::endl;
    
    std::istream is(&sb);
    std::string s;
    is >> s;
    std::cout << "str = " << s << std::endl;
}

上一个例子,你会发现,直接硬撸内部数据结构,对input_sequence没有副作用。所以你应该用另一个函数叫做consume()的,让流缓冲内部的管理指针移动。

int main()
{
    boost::asio::streambuf sb ;
        
    std::ostream os(&sb);
    os << "1234567890";
    
    
    auto input_sequence = sb.data();
    std::string str(boost::asio::buffers_begin(input_sequence),
                    boost::asio::buffers_begin(input_sequence) + 10);
    std::cout << "str = " << str << std::endl;
    
    sb.consume(10);
    
    std::istream is(&sb);
    std::string s;
    is >> s;
    std::cout << "str = " << s << std::endl;
}

明白了consume()和data()的关系,就能理解socket类发送数据到网络上去时,它是从inuput_sequence读取数据的。

boost::asio::streambuf b;    
std::ostream os(&b);

for (int i=0;i<100000;++i){
    os << "1234567890" ;
}

do {
    size_t n = sock.send(b.data());
    b.consume(n); //如果没有这句话,就变成一个黑客攻击行为了,不停的发数据
}while(n>0)

理解了consume()和data()的关系,就差不多猜到commit()和prepare()的关系。prepare()直接拿到output_sequence去操作。所以它不能把数据自动转移到input_sequence里,需要手动commit一下

asio::streambuf sb;
auto output_sequence = b.prepare(512); //直接拿到output_sequence
size_t n = sock.receive(output_sequence);
sb.commit(n); //送到input sequence里

const char *data_ptr = boost::asio::buffer_cast<const char*>(sb->data());
std::string line(data_ptr ,data_ptr+n);
sb.consume(n);

但是,如果是直接使用streambuf去操作socket类,就不需要显式的commit()或consume()

boost::asio::streambuf sb;

boost::asio::async_read_until(socket,sb, ......, );


//回调函数处
boost::asio::streambuf::const_buffers_type bufs = sb.data();
std::string line(boost::asio::buffers_begin(bufs), boost::asio::buffers_begin(bufs) + n);

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Boost.Asio 是一个 C++ 网络编程库,可以用于开发高性能的网络应用程序。使用 Boost.Asio,你可以轻松地实现异步网络编程,包括 TCP、UDP、SSL、HTTP 等协议。 下面是一个简单的 Boost.Asio 示例,演示如何使用异步 TCP 客户端: ```cpp #include <boost/asio.hpp> #include <iostream> using boost::asio::ip::tcp; int main() { boost::asio::io_context io_context; tcp::resolver resolver(io_context); tcp::resolver::results_type endpoints = resolver.resolve("www.baidu.com", "80"); tcp::socket socket(io_context); boost::asio::connect(socket, endpoints); boost::asio::streambuf request; std::ostream request_stream(&request); request_stream << "GET / HTTP/1.1\r\n"; request_stream << "Host: www.baidu.com\r\n"; request_stream << "Connection: close\r\n\r\n"; boost::asio::async_write(socket, request, [](const boost::system::error_code& error, std::size_t bytes_transferred) { if (!error) { std::cout << "Sent " << bytes_transferred << " bytes." << std::endl; } else { std::cerr << "Error: " << error.message() << std::endl; } }); boost::asio::streambuf response; boost::asio::async_read_until(socket, response, "\r\n", [&response](const boost::system::error_code& error, std::size_t bytes_transferred) { if (!error) { std::istream response_stream(&response); std::string http_version; response_stream >> http_version; std::cout << "HTTP version: " << http_version << std::endl; } else { std::cerr << "Error: " << error.message() << std::endl; } }); io_context.run(); return 0; } ``` 这个示例中,我们使用了 Boost.Asio 的异步 API,首先通过 DNS 解析获取到百度的 IP 地址,然后连接到百度的 80 端口,发送一个 HTTP GET 请求,最后读取响应并输出 HTTP 版本号。 需要注意的是,Boost.Asio 的异步 API 需要使用 io_context 来驱动事件循环,我们在最后调用 io_context.run() 来启动事件循环。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值