boost::asio中的buffer与streambuf简介

boost::asio在处理I/O操作时支持两种类型的buffer:

  • boost::asio::buffer():本身并不申请内存,只是提供了一个对现有内存的封装。

  • boost::asio::streambuf:提供了一个流类型的buffer(这个buffer继承自std::streambuf),它自身根据需要动态申请内存的,。并且可以和STL stream一起使用。就像std::streambuf本身,它不能拷贝构造

 


boost::asio::buffer

1、buffer创建

buffer可方便的从‘字符数组’、‘vector向量’、‘字符串’中创建。

char buff[1024];

read(sock, buffer(buff), read_complete);

string str = "hello";

write(sock, buffer(str));

 

2、从buffer中获取数据

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

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

 

3、操作buffer

  • socket(如tcp::socke)对象中提供的read_some和write_some;

  • asio名字空间下的read、write函数,提供了更高级的操作;

  • 与以下函数配合可方便读写:

    • transfer_at_least(n)

    • transfer_exactly(n)

    • transfer_all()

 

async_read(sock, buffer(buff), transfer_exactly(32), on_read)。

 


boost::asio::streambuf

streambuf对象可自己动态分配内存,所以相当于是一个无限大小的缓冲区。

streambuf buf;

std::ostream out(&buf);

out << "hello" << std::endl;

write(sock, buf);

// 转换为string

 

std::ostringstream str;

str << &buf;

cout<<str.str()<<endl;

 

一些方法说明:

  • streambuf([max_size,][allocator]):这个方法构造了一个streambuf对象。可以指定一个最大的buffer大小,和一个分配器。

  • prepare(n):这个方法返回一个子大小为n的buffer用来读取或者写入(可以在任何Boost.Asio处理read/write的自由函数中使用)。read/write后,原buffer指针并没有移动,若要操作数据需要使用consume或commit来处理指针:    

    read(sock, buf.prepare(16), transfer_exactly(16) );

    buf.commit(16); // 若不commit,则下面输出为空

    std::cout << &buf << std::endl;

  • data():以连续的字符串形式返回整个buffer然后用来写入(可以在任何Boost.Asio处理写入的自由函数中使用)。

  • comsume(n):在这个方法中,数据从输入队列中被移除(从read操作)

  • commit(n):在这个方法中,数据从输出队列中被移除(从write操作)然后加入到输入队列中(为read操作准备)。

  • size():这个方法以字节为单位返回整个streambuf对象的大小。

  • max_size():这个方法返回最多能保存的字节数。

 

streambuf buf;

read(sock, buf);

未指定buffer大小,会一直读取,直到sock关闭或内存不足。

 

可以使用read_until一直读到一个特定的字符串,如读取一行:

streambuf buf;

read_until(sock, buf, "\n");

 

一直读取直到读到一个元音字母

streambuf buf;

bool is_vowel(char c) {

    return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c =='u';

}

 typedef buffers_iterator<streambuf::const_buffers_type> iterator

std::pair<iterator,bool> match_vowel(iterator b, iterator e) {

    while ( b != e)

    if ( is_vowel(*b++)) return std::make_pair(b, true);

        return std::make_pair(e, false);

} .

..

size_t bytes = read_until(sock, buf, match_vowel);

// 或直接使用正则表达式

read_until(sock, buf, boost::regex("^[aeiou]+") );

 


自由函数

Boost.Asio中处理buffer对象的自由函数:

  • read(sock, buf[, completion_function]):这个方法把内容从socket读取到streambuf对象中。completion方法是可选的,若有则在每次read操作成功之后被调用,以告诉Boost.Asio这个操作是否完成。

    size_t completion(const boost::system::error_code &err, size_t bytes_transfered);

    • 若返回0,表示read操作完成了;

    • 若返回非0,表示下一次调用stream的read_some方法需要读取的最大字节数。

  • read_at(random_stream, offset, buf [, completion_function]): 这个方法从一个支持随机读取的stream中读取。注意它没有被应用到socket中(因为他们没有随机读取的模型,它们是单向的,一直向前) 。

  • read_until(sock, buf, char | string | regex | match_condition): 这个方法一直读到满足一个特性的条件为止。或者是一个char类型的数据被读到,或者是一个字符串被读到,或者是一个目前读到的字符串能匹配的正则表达式,或者match_condition方法告诉我们需要结束这个方法。

    match_condition方法的格式是:

    pair match(iterator begin, iterator end); 

    • iterator代表 buffers_iterator。如果匹配到,返回一个pair<iterator, true>(iterator为当前操作的位置,即匹配的地方) 。

    • 如果没有匹配到,返回pair<iterator, false> 。

  • write(sock, buf [, completion_function]): 这个方法写入streambuf对象所有的内容。completion方法是可选的,它的表现和read()的completion方法类似:

    • 返回0,当write操作完成时;

    • 返回一个非0数代表下一次调用stream的write_some方法需要写入的最大的字节数。

  • write_at(random_stream,offset, buf [, completion_function]): 这个方法用来向一个支持随机存储的stream写入。同样,它没有被应用到socket中

  • async_read(sock, buf [, competion_function], handler): 这个方法是read()的异步实现,handler的格式为:void handler(const boost::system::error_code, size_t bytes)。

  • async_read_at(random_stream, offset, buf [, completion_function] , handler):这个方法是read_at()的异步实现。

  • asyncread_until (sock, buf, char | string | regex | match condition, handler): 这个方法是read_until()的异步实现。

  • async_write(sock, buf [, completion_function] , handler): 这个方法是write()的异步实现。

  • async_write_at(random_stream,offset, buf [, completion_function] , handler):这个方法是write_at()的异步实现。

 

这些函数不只能用于sock读写,还能用于所有符合条件流的读写;如读写windows下的文件:

HANDLE file = ::CreateFile("readme.txt", GENERIC_READ, 0, 0, OPE

N_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0);

windows::stream_handle h(service, file);

streambuf buf;

int bytes = read_until(h, buf, '\n');

std::istream in(&buf);

std::string line;

std::getline(in, line);

// 或使用随机获取句柄

 

// windows::random_access_handle h(service, file);

// char buf[50];

// int bytes = read_at(h, 1000, buffer( buf));

// std::string msg(buf, bytes);

std::cout << line << std::endl;

 

类似地,使用object_handle也可以封装windows的事件句柄,以便使用asio中的wait自由函数:

void on_wait_complete(boost::system::error_code err) {}

HANDLE evt = ::CreateEvent(NULL, true, true, 0);

windows::object_handle h(service, evt);

h.wait();

// 或异步等待

// h.async_wait(on_wait_complete);

好的,我可以为你提供一些关于如何使用boostasio编写服务器的基本步骤。首先,你需要使用boost asio库来编写网络服务器,以下是基本的实现步骤: 1. 创建一个socket,绑定并监听特定的端口号。可以使用 boost::asio::io_service 类来启动一个 I/O(input/output) 服务。 2. 在新连接到来时,使用 accept() 函数接收连接请求并创建新的 socket 对象。 3. 通过读写socket来与客户端进行通信。可以使用 boost::asio::read() 和 boost::asio::write() 函数来实现数据的读取和发送。 下面是一个简单的代码示例: ```c++ #include <boost/asio.hpp> #include <iostream> using boost::asio::ip::tcp; int main() { try { boost::asio::io_service io_service; //监听端口号 tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 1234)); while (true) { //等待新的连接请求 tcp::socket socket(io_service); acceptor.accept(socket); //向客户端发送欢迎消息 std::string message = "Welcome to server!"; boost::asio::write(socket, boost::asio::buffer(message)); //接收客户端消息并打印到控制台 boost::asio::streambuf buf; boost::asio::read_until(socket, buf, '\n'); std::string data = boost::asio::buffer_cast<const char*>(buf.data()); std::cout << "Client says: " << data << std::endl; } } catch (std::exception& e) { std::cerr << e.what() << std::endl; } return 0; } ``` 上面的代码演示了一个简单的 TCP 服务器实现,该服务器会监听本地的 1234 端口,并在客户端连接成功后向客户端发送欢迎消息,然后从客户端接收消息并将其打印在服务器的控制台上。 需要注意的是,上述代码仅仅是一个简单的示例,并不涉及很多网络编程需要考虑的细节问题。如果需要开发一个实际的生产服务器,还需要考虑诸如线程池、异常处理、安全性等问题,这些问题需要根据具体情况进行详细的实现和测试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值