read/write/connect自由函数

来源:互联网 发布:如何登录淘宝账户 编辑:程序博客网 时间:2024/06/09 17:54

Boost.Asio提供了处理I/O的自由函数,我们分四组来分析它们。

1. connect方法

这些方法把套接字连接到一个端点。

connect(socket, begin [, end] [, condition]):

这个方法遍历队列中从start到end的端点来尝试同步连接。begin迭代器是调用socket_type::resolver::query的返回结果(你可能需要回顾一下端点这个章节)。特别提示end迭代器是可选的;你可以忽略它。

你还可以提供一个condition的方法给每次连接尝试之后调用。用法是Iterator connect_condition(const boost::system::error_code & err,Iterator next);。

你可以选择返回一个不是next的迭代器,这样你就可以跳过一些端点。

async_connect(socket, begin [, end] [, condition], handler):

这个方法异步地调用连接方法,在结束时,它会调用完成处理方法。用法是void handler(constboost::system::error_code & err, Iterator iterator);。

传递给处理方法的第二个参数是连接成功端点的迭代器(或者end迭代器)。

它的例子如下:

using namespace boost::asio::ip;

tcp::resolver resolver(service);

tcp::resolver::iterator iter = resolver.resolve(tcp::resolver::query("www.yahoo.com","80"));

tcp::socket sock(service);

一个主机名可以被解析成多个地址,而connect和async_connect能很好地把你从尝试每个地址然后找到一个可用地址的繁重工作中解放出来,因为它们已经帮你做了这些。

2. read/write方法

这些方法对一个流进行读写操作(可以是套接字,或者其他表现得像流的类):

async_read(stream, buffer [, completion] ,handler):

这个方法异步地从一个流读取。结束时其处理方法被调用。处理方法的格式是:void handler(const boost::system::error_ code & err, size_t bytes);。

你可以选择指定一个完成处理方法。完成处理方法会在每个read操作调用成功之后调用,然后告诉Boost.Asio async_read操作是否完成(如果没有完成,它会继续读取)。

它的格式是:size_tcompletion(const boost::system::error_code& err, size_t bytes_transfered) 。

当这个完成处理方法返回0时,我们认为read操作完成;如果它返回一个非0值,它表示了下一个async_read_some操作需要从流中读取的字节数。接下来会有一个例子来详细展示这些。


async_write(stream, buffer [, completion], handler):

这个方法异步地向一个流写入数据。参数的意义和async_read是一样的。

read(stream, buffer [, completion]):

这个方法同步地从一个流中读取数据。参数的意义和async_read是一样的。

write(stream, buffer [, completion]):

这个方法同步地向一个流写入数据。参数的意义和async_read是一样的。

async_read(stream, stream_buffer [, completion], handler)

async_write(strean, stream_buffer [, completion], handler)

write(stream, stream_buffer [, completion])

read(stream, stream_buffer [, completion])

首先,要注意第一个参数变成了流,而不单是socket。这个参数包含了socket但不仅仅是socket。

比如,你可以用一个Windows的文件句柄来替代socket。 当下面情况出现时,所有read和write操作都会结束:

  • 可用的缓冲区满了(当读取时)或者所有的缓冲区已经被写入(当写入时)
  • 完成处理方法返回0(如果你提供了这么一个方法)
  • 错误发生时

下面的代码会异步地从一个socket中间读取数据直到读取到’\n’:

io_service service;

ip::tcp::socket sock(service);

char buff[512];

int offset = 0;

size_t up_to_enter(const boost::system::error_code &, size_t bytes) {

for ( size_t i = 0; i < bytes; ++i)

if ( buff[i + offset] == '\n')

return 0;

return 1;

}

void on_read(const boost::system::error_code &, size_t) {}

...

async_read(sock, buffer(buff), up_to_enter, on_read);

Boost.Asio也提供了一些简单的完成处理仿函数:

  • transfer_at_least(n)
  • transfer_exactly(n)
  • transfer_all()

例子如下:
char buff[512];
void on_read(const boost::system::error_code &, size_t) {}
// 读取32个字节
async_read(sock, buffer(buff), transfer_exactly(32), on_read);
上述的4个方法,不使用普通的缓冲区,而使用由Boost.Asio的std::streambuf类继承来的stream_buffer方
法。stl流和流缓冲区非常复杂;下面是例子:
io_service service;
void on_read(streambuf& buf, const boost::system::error_code &, size_t) {
std::istream in(&buf);
std::string line;
std::getline(in, line);
std::cout << "first line: " << line << std::endl;
}
int main(int argc, char* argv[]) {
HANDLE file = ::CreateFile("readme.txt", GENERIC_READ, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | windows::stream_handle h(service, file);
streambuf buf;
async_read(h, buf, transfer_exactly(256), boost::bind(on_read,boost::ref(buf),_1,_2));
service.run();
}
在这里,我向你们展示了在一个Windows文件句柄上调用async_read。读取前256个字符,然后把它们保
存到缓冲区中,当操作结束时。on_read被调用,再创建std::istream用来传递缓冲区,读取第一行
(std::getline),最后把它输出到命令行中。

3. read_until/async_read_until方法

这些方法在条件满足之前一直读取:
async_read_until(stream, stream_buffer, delim, handler):这个方法启动一个异步read操作。read操作
会在读取到某个分隔符时结束。分隔符可以是字符,std::string或者boost::regex。处理方法的格式
为:void handler(const boost::system::error_code & err, size_t bytes);。
async_read_until(strem, stream_buffer, completion, handler):这个方法和之前的方法是一样的,但是
没有分隔符,而是一个完成处理方法。完成处理方法的格式为:pair< iterator,bool >
completion(iterator begin, iterator end);,其中迭代器的类型为buffers_iterator<
streambuf::const_buffers_type >。你需要记住的是这个迭代器是支持随机访问的。你扫描整个区间
(begin,end),然后决定read操作是否应该结束。返回的结果是一个结果对,第一个成员是一个迭
代器,它指向最后被这个方法访问的字符;第二个成员指定read操作是否需要结束,需要时返回true,
否则返回false。
read_until(stream, stream_buffer, delim):这个方法执行一个同步的read操作,参数的意义和
async_read_until一样。
read_until(stream, stream_buffer, completion):这个方法执行一个同步的read操作,参数的意义和
async_read_until一样。
下面这个例子在读到一个指定的标点符号之前会一直读取:
typedef buffers_iterator<streambuf::const_buffers_type> iterator;
std::pair<iterator, bool> match_punct(iterator begin, iterator end) {
while ( begin != end)
if ( std::ispunct(*begin))
return std::make_pair(begin,true);
return std::make_pair(end,false);
}
void on_read(const boost::system::error_code &, size_t) {}
...
streambuf buf;
async_read_until(sock, buf, match_punct, on_read);
如果我们想读到一个空格时就结束,我们需要把最后一行修改为:
read_until/async_read_until方法
async_read_until(sock, buff, ' ', on_read);

4. *_at方法

这些方法用来在一个流上面做随机存取操作。由你来指定read和write操作从什么地方开始(offset):
async_read_at(stream, offset, buffer [, completion], handler):这个方法在指定的流的offset处开始执
行一个异步的read操作,当操作结束时,它会调用handler。handler的格式为:void handler(const
boost::system::error_code& err, size_t bytes);。buffer可以是普通的wrapper()封装或者streambuf方
法。如果你指定一个completion方法,它会在每次read操作成功之后调用,然后告诉Boost.Asio
async_read_at操作已经完成(如果没有,则继续读取)。它的格式为:size_t completion(const
boost::system::error_code& err, size_t bytes);。当completion方法返回0时,我们认为read操作完成
了;如果返回一个非零值,它代表了下一次调用流的async_read_some_at方法的最大读取字节数。
async_write_at(stream, offset, buffer [, completion], handler):这个方法执行一个异步的write操作。参
数的意义和async_read_at是一样的
read_at(stream, offset, buffer [, completion]):这个方法在一个执行的流上,指定的offset处开始
read。参数的意义和async_read_at是一样的
write_at(stream, offset, buffer [, completion]):这个方法在一个执行的流上,指定的offset处开始
write。参数的意义和async_read_at是一样的
这些方法不支持套接字。它们用来处理流的随机访问;也就是说,流是可以随机访问的。套接字显然不是
这样(套接字是不可回溯的)。
下面这个例子告诉你怎么从一个文件偏移为256的位置读取128个字节:
io_service service;
int main(int argc, char* argv[]) {
HANDLE file = ::CreateFile("readme.txt", GENERIC_READ, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | windows::random_access_handle h(service, file);
streambuf buf;
read_at(h, 256, buf, transfer_exactly(128));
std::istream in(&buf);
std::string line;
std::getline(in, line);
std::cout << "first line: " << line << std::endl;
}

0 0
原创粉丝点击