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(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

write(sock, buf);

// 转换为string

std::ostringstream str;

cout

一些方法说明:

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

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 iterator;

std::pair 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为当前操作的位置,即匹配的地方) 。

如果没有匹配到,返回pair 。

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_handleh(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_handleh(service, file);

//char buf[50];

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

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

std::cout

类似地,使用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);

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180701G0CJOC00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券