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);
领取专属 10元无门槛券
私享最新 技术干货