Boost AISO官方教程翻译版

目录

I/O Services and I/O Objects

Scalability and Multithreading

Network programming

Coroutines

Platform-specific I/O Objects


I/O Services and I/O Objects

Abstract

Programs that use Boost.Asio for asynchronous data processing are based on I/O services and I/O objects. I/O services abstract the operating system interfaces that process data asynchronously. I/O objects initiate asynchronous operations. These two concepts are required to separate tasks cleanly: I/O services look towards the operating system API, and I/O objects look towards tasks developers need to do.

使用Boost的程序。异步数据处理的Asio是基于I/O服务和I/O对象的。

I/O服务本质上是抽象了异步处理数据的操作系统接口。

I/O对象则是发起的异步操作。

这两个概念用于清晰地分离任务与调度器:

I/O服务着眼于操作系统API可以理解为上下文调度管理,而I/O对象着眼于开发人员需要完成的任务。

How

As a user of Boost.Asio you normally don’t connect with I/O services directly. I/O services are managed by an I/O service object. An I/O service object is like a registry where I/O services are listed. Every I/O object knows its I/O service and gets access to its I/O service through the I/O service object.

在使用ASIO I/O service 的时候,不需要直接去连接操作service,I/Oservice 就像是一个注册表一样,可以将我们的一些异步操作注册在里面,每个I/Oservice 对象独立管理自己的操作。

Boost.Asio defines boost::asio::io_service, a single class for an I/O service object. Every program based on Boost.Asio uses an object of type boost::asio::io_service. This can also be a global variable.

While there is only one class for an I/O service object, several classes for I/O objects exist. Because I/O objects are task oriented, the class that needs to be instantiated depends on the task. For example, if data has to be sent or received over a TCP/IP connection, an I/O object of type boost::asio::ip::tcp::socket can be used. If data has to be transmitted asynchronously over a serial port, boost::asio::serial_port can be instantiated. If you want to wait for a time period to expire, you can use the I/O object boost::asio::steady_timer.

boost::asio::steady_timer is like an alarm clock. Instead of waiting for a blocking function to return when the alarm clock rings, your program will be notified. Because boost::asio::steady_timer just waits for a time period to expire, it would seem as though no external resource is accessed. However, in this case the external resource is the capability of the operating system to notify a program when a time period expires. This frees a program from creating a new thread just to call a blocking function. Since boost::asio::steady_timer is a very simple I/O object, it will be used to introduce Boost.Asio.

简单的说,这里面有几个核心的api、类,包括了io_service(IO管理器), ip::tcp::socket(socket连接器),串口(serial_port),定时器(steady_time)

Demo

#include <boost/asio/io_service.hpp>
#include <boost/asio/steady_timer.hpp>
#include <chrono>
#include <iostream>

using namespace boost::asio;

int main()
{
  io_service ioservice;

  steady_timer timer{ioservice, std::chrono::seconds{3}};
  timer.async_wait([](const boost::system::error_code &ec)
    { std::cout << "3 sec\n"; });

  ioservice.run();
}

Example 32.1 creates an I/O service object, ioservice, and uses it to initialize the I/O object timer. Like boost::asio::steady_timer, all I/O objects expect an I/O service object as a first parameter in their constructor. Since timer represents an alarm clock, a second parameter can be passed to the constructor of boost::asio::steady_timer that defines the specific time or time period when the alarm clock should ring. In Example 32.1, the alarm clock is set to ring after 3 seconds. The time starts with the definition of timer.

Instead of calling a blocking function that will return when the alarm clock rings, Boost.Asio lets you start an asynchronous operation. To do this, call the member function async_wait(), which expects a handler as the sole parameter. A handler is a function or function object that is called when the asynchronous operation ends. In Example 32.1, a lambda function is passed as a handler.

async_wait() returns immediately. Instead of waiting three seconds until the alarm clock rings, the lambda function is called after three seconds. When async_wait() returns, a program can do something else.

A member function like async_wait() is called non-blocking. I/O objects usually also provide blocking member functions as alternatives. For example, you can call the blocking member function wait() on boost::asio::steady_timer. Because this member function is blocking, no handler is passed. wait() returns at a specific time or after a time period.

上述的代码,本质上就是一个协程的典型应用,async_wait()会立即返回。不是等待三秒直到闹钟响,而是在三秒后调用lambda函数。当async_wait()返回时,程序可以执行其他操作。

像async_wait()这样的成员函数被称为非阻塞函数。I/O对象通常也提供阻塞成员函数作为替代。例如,你可以在boost::asio::steady_timer上调用阻塞成员函数wait()。因为这个成员函数是阻塞的,所以没有传递处理程序。Wait()在特定时间或一段时间后返回。

#include <boost/asio/io_service.hpp>
#include <boost/asio/steady_timer.hpp>
#include <chrono>
#include <iostream>

using namespace boost::asio;

int main()
{
  io_service ioservice;

  steady_timer timer1{ioservice, std::chrono::seconds{3}};
  timer1.async_wait([](const boost::system::error_code &ec)
    { std::cout << "3 sec\n"; });

  steady_timer timer2{ioservice, std::chrono::seconds{4}};
  timer2.async_wait([](const boost::system::error_code &ec)
    { std::cout << "4 sec\n"; });

  ioservice.run();
}

In Example 32.2, two objects of type boost::asio::steady_timer are used. The first I/O object is an alarm clock that rings after three seconds. The other is an alarm clock ringing after four seconds. After both time periods expire, the lambda functions that were passed to async_wait() will be called.

run() is called on the only I/O service object in this example. This call passes control to the operating system functions that execute asynchronous operations. With their help, the first lambda function is called after three seconds and the second lambda function after four seconds.

It might come as a surprise that asynchronous operations require a call to a blocking function. However, this is not a problem because the program has to be prevented from exiting. If run() wouldn’t block, main() would return, and the program would exit. If you don’t want to wait for run() to return, you only need to call run() in a new thread.

The reason why the examples above exit after a while is that run() returns if there are no pending asynchronous operations. Once all alarm clocks have rung, no asynchronous operations exist that the program needs to wait for.

ioservice.run()会导致程序阻塞直到所有的异步操作全部执行完毕。

Scalability and Multithreading

Abstract

Developing a program based on a library like Boost.Asio differs from the usual C++ style. Functions that may take longer to return are no longer called in a sequential manner. Instead of calling blocking functions, Boost.Asio starts asynchronous operations. Functions which should be called after an operation has finished are now called within the corresponding handler. The drawback of this approach is the physical separation of sequentially executed functions, which can make code more difficult to understand.

A library such as Boost.Asio is typically used to achieve greater efficiency. With no need to wait for an operation to finish, a program can perform other tasks in between. Therefore, it is possible to start several asynchronous operations that are all executed concurrently – remember that asynchronous operations are usually used to access resources outside of a process. Since these resources can be different devices, they can work independently and execute operations concurrently.

Scalability describes the ability of a program to effectively benefit from additional resources. With Boost.Asio it is possible to benefit from the ability of external devices to execute operations concurrently. If threads are used, several functions can be executed concurrently on available CPU cores. Boost.Asio with threads improves the scalability because your program can take advantage of internal and external devices that can execute operations independently or in cooperation with each other.

如果在boost::asio::io_service类型的对象上调用成员函数run(),那么关联的处理程序将在同一个线程中调用。通过使用多线程,程序可以多次调用run()。一旦异步操作完成,I/O服务对象将在其中一个线程中执行处理程序。如果第二个操作在第一个操作之后不久完成,那么I/O服务对象可以在另一个线程中执行处理程序。现在,不仅进程外的操作可以并发执行,进程内的处理程序也可以并发执行。

Demo

#include <boost/asio/io_service.hpp>
#include <boost/asio/steady_timer.hpp>
#include <chrono>
#include <thread>
#include <iostream>

using namespace boost::asio;

int main()
{
  io_service ioservice;

  steady_timer timer1{ioservice, std::chrono::seconds{3}};
  timer1.async_wait([](const boost::system::error_code &ec)
    { std::cout << "3 sec\n"; });

  steady_timer timer2{ioservice, std::chrono::seconds{3}};
  timer2.async_wait([](const boost::system::error_code &ec)
    { std::cout << "3 sec\n"; });

  std::thread thread1{[&ioservice](){ ioservice.run(); }};
  std::thread thread2{[&ioservice](){ ioservice.run(); }};
  thread1.join();
  thread2.join();
}

前面的示例已在示例32.3中转换为多线程程序。使用std::thread,在main()中创建两个线程。run()在每个线程中唯一的I/O服务对象上调用。这使得当异步操作完成时,I/O服务对象可以使用两个线程来执行处理程序。

在例32.3中,两个闹钟都应该在三秒后响起。因为有两个线程可用,所以两个lambda函数都可以并发执行。如果第一个闹钟的处理程序正在执行时第二个闹钟响了,那么这个处理程序可以在第二个线程中执行。如果第一个闹钟的处理程序已经返回,那么I/O服务对象可以使用任何线程来执行第二个处理程序。

当然,使用线程并不总是有意义的。例32.3可能不会按顺序将消息写入标准输出流。相反,它们可能被混淆了。两个处理程序可以同时在两个线程中运行,它们共享全局资源std::cout。为了避免中断,对std::cout的访问需要同步。如果处理程序不能并发执行,那么线程的优势就会丧失。

#include <boost/asio/io_service.hpp>
#include <boost/asio/steady_timer.hpp>
#include <chrono>
#include <thread>
#include <iostream>

using namespace boost::asio;

int main()
{
  io_service ioservice1;
  io_service ioservice2;

  steady_timer timer1{ioservice1, std::chrono::seconds{3}};
  timer1.async_wait([](const boost::system::error_code &ec)
    { std::cout << "3 sec\n"; });

  steady_timer timer2{ioservice2, std::chrono::seconds{3}};
  timer2.async_wait([](const boost::system::error_code &ec)
    { std::cout << "3 sec\n"; });

  std::thread thread1{[&ioservice1](){ ioservice1.run(); }};
  std::thread thread2{[&ioservice2](){ ioservice2.run(); }};
  thread1.join();
  thread2.join();
}

在单个I/O服务对象上反复调用run()是编写基于Boost的程序的推荐方法。Asio更具有可伸缩性。但是,您可以创建多个I/O服务对象,而不是为一个I/O服务对象提供多个线程。

在例32.4中,在boost::asio::steady_timer类型的两个闹钟旁边使用两个I/O服务对象。该程序基于两个线程,每个线程绑定到另一个I/O服务对象。两个I/O对象timer1和timer2不再绑定同一个I/O服务对象。它们被绑定到不同的对象。

例32.4的工作方式与以前相同。不可能给出关于何时使用多个I/O服务对象有意义的一般性建议。因为boost::asio::io_service代表一个操作系统接口,任何决策都取决于特定的接口。

在Windows上,boost::asio::io_service通常基于IOCP,在Linux上,它基于epoll()。拥有多个I/O服务对象意味着将使用多个I/O完成端口,或者将多次调用epoll()。这是否比只使用一个I/O完成端口或调用epoll()更好,取决于具体情况。

Other

除此之外,还有一个基于io_service 的类,名字叫strand, 最大的区别就是strand 是同步执行被管理的操作,顺序就是注册操作的顺序。

Network programming

Abstract

Even though Boost.Asio can process any kind of data asynchronously, it is mainly used for network programming. This is because Boost.Asio supported network functions long before additional I/O objects were added. Network functions are a perfect use for asynchronous operations because the transmission of data over a network may take a long time, which means acknowledgments and errors may not be available as fast as the functions that send or receive data can execute.

尽管Asio可以异步处理任何类型的数据,但是主要用于网络编程。这是因为Boost早在添加额外的I/O对象之前,Asio就已经支持网络功能了。网络函数是异步操作的完美应用,因为通过网络传输数据可能需要很长时间,这意味着确认和错误可能没有发送或接收数据的函数执行得快。

Demo

#include <boost/asio/io_service.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <array>
#include <string>
#include <iostream>

using namespace boost::asio;
using namespace boost::asio::ip;

io_service ioservice;
tcp::resolver resolv{ioservice};
tcp::socket tcp_socket{ioservice};
std::array<char, 4096> bytes;

void read_handler(const boost::system::error_code &ec,
  std::size_t bytes_transferred)
{
  if (!ec)
  {
    std::cout.write(bytes.data(), bytes_transferred);
    tcp_socket.async_read_some(buffer(bytes), read_handler);
  }
}

void connect_handler(const boost::system::error_code &ec)
{
  if (!ec)
  {
    std::string r =
      "GET / HTTP/1.1\r\nHost: theboostcpplibraries.com\r\n\r\n";
    write(tcp_socket, buffer(r));
    tcp_socket.async_read_some(buffer(bytes), read_handler);
  }
}

void resolve_handler(const boost::system::error_code &ec,
  tcp::resolver::iterator it)
{
  if (!ec)
    tcp_socket.async_connect(*it, connect_handler);
}

int main()
{
  tcp::resolver::query q{"theboostcpplibraries.com", "80"};
  resolv.async_resolve(q, resolve_handler);
  ioservice.run();
}


在main()中,boost::asio::ip::tcp::resolver::query实例化创建一个q对象。q表示对名称解析器的查询,这是一个boost::asio::ip::tcp::resolver类型的I/O对象。通过将q传递给async_resolve(),将启动一个异步操作来解析名称。解析名称theboostcpplibraries.com。异步操作启动后,在I/O服务对象上调用run(),将控制权传递给操作系统。

当名称被解析后,将调用resolve_handler()。处理程序首先检查名称解析是否成功。这里ec等于0。只有这样,才能访问套接字来建立连接。要连接的服务器地址由第二个参数提供,类型为boost::asio::ip::tcp::resolver::iterator。该参数是名称解析的结果。

对async_connect()的调用之后是对处理程序connect_handler()的调用。同样,首先检查ec以确定是否可以建立连接。如果是,则在套接字上调用async_read_some()。通过这个调用,开始读取数据。接收到的数据存储在数组字节中,它作为第一个参数传递给async_read_some()。

当接收到一个或多个字节并复制到字节中时,调用Read_handler()。类型为std::size_t的bytes_transferred参数包含已经接收到的字节数。通常,处理程序应该首先检查异步操作是否成功完成。只有在这种情况下,才会将数据写入标准输出。

请注意,read_handler()在数据写入std::cout之后再次调用async_read_some()。这是必需的,因为您不能确定在单个异步操作中下载了整个主页并将其复制到字节中。重复调用async_read_some(),然后重复调用read_handler(),只有当连接关闭时才结束,这发生在web服务器已经发送了整个主页。然后read_handler()报告ec中的错误。此时,没有进一步的数据写入std::cout,并且不会在套接字上调用async_read()。因为没有挂起的异步操作,所以程序退出。

#include <boost/asio/io_service.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <string>
#include <ctime>

using namespace boost::asio;
using namespace boost::asio::ip;

io_service ioservice;
tcp::endpoint tcp_endpoint{tcp::v4(), 2014};
tcp::acceptor tcp_acceptor{ioservice, tcp_endpoint};
tcp::socket tcp_socket{ioservice};
std::string data;

void write_handler(const boost::system::error_code &ec,
  std::size_t bytes_transferred)
{
  if (!ec)
    tcp_socket.shutdown(tcp::socket::shutdown_send);
}

void accept_handler(const boost::system::error_code &ec)
{
  if (!ec)
  {
    std::time_t now = std::time(nullptr);
    data = std::ctime(&now);
    async_write(tcp_socket, buffer(data), write_handler);
  }
}

int main()
{
  tcp_acceptor.listen();
  tcp_acceptor.async_accept(tcp_socket, accept_handler);
  ioservice.run();
}

这是一个时间服务器。您可以与telnet客户端连接以获得当前时间。之后,时间服务器关闭。

tcp::v4() 可以替换为address_type::from_string("127.0.0.1")。

时间服务器使用I/O对象boost::asio::ip::tcp::acceptor来接收来自另一个程序的连接。您必须初始化对象,以便它知道在哪个端口上使用哪个协议。在这个例子中,类型为boost::asio::ip::tcp::endpoint的变量tcp_endpoint被用来告诉tcp_acceptor在端口2014上接受互联网协议版本4的传入连接。

在接受者初始化之后,调用listen()来使接受者开始监听。然后调用async_accept()来接受第一次连接尝试。套接字必须作为第一个参数传递给async_accept(),它将用于在新连接上发送和接收数据。

一旦另一个程序建立连接,就调用accept_handler()。如果连接建立成功,当前时间将通过boost::asio::async_write()发送。这个函数将data中的所有数据写入套接字。Boost::asio::ip::tcp::socket还提供了成员函数async_write_some()。当至少发送了一个字节时,这个函数调用处理程序。然后,处理程序必须检查已经发送了多少字节,还有多少字节需要发送。然后,它必须再次调用async_write_some()。可以通过boost::asio::async_write()来避免重复计算剩余的发送字节数和调用async_write_some()。由这个函数开始的异步操作只有在数据中的所有字节都已发送后才会完成。

发送数据之后,调用write_handler()。这个函数调用shutdown(),参数是boost::asio::ip::tcp::socket::shutdown_send,表示程序通过socket发送数据已经完成。由于没有等待的异步操作,示例32.6退出。请注意,尽管data仅用于accept_handler()中,但它不能是局部变量。数据通过boost::asio::buffer()传递给boost::asio::async_write()。当boost::asio::async_write()和accept_handler()返回时,异步操作已经启动,但还没有完成。在异步操作完成之前,数据必须存在。如果data是一个全局变量,这是可以保证的。

Coroutines

Abstract

Since version 1.54.0, Boost.Asio supports coroutines. While you could use Boost.Coroutine directly, explicit support of coroutines in Boost.Asio makes it easier to use them.

Coroutines let you create a structure that mirrors the actual program logic. Asynchronous operations don’t split functions, because there are no handlers to define what should happen when an asynchronous operation completes. Instead of having handlers call each other, the program can use a sequential structure.

从版本1.54.0开始,Boost。Asio支持协同程序。而您可以使用Boost。直接协程,在Boost中显式支持协程。Asio使它们更容易使用。

Demo

#include <boost/asio/io_service.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <list>
#include <string>
#include <ctime>

using namespace boost::asio;
using namespace boost::asio::ip;

io_service ioservice;
tcp::endpoint tcp_endpoint{tcp::v4(), 2014};
tcp::acceptor tcp_acceptor{ioservice, tcp_endpoint};
std::list<tcp::socket> tcp_sockets;

void do_write(tcp::socket &tcp_socket, yield_context yield)
{
  std::time_t now = std::time(nullptr);
  std::string data = std::ctime(&now);
  async_write(tcp_socket, buffer(data), yield);
  tcp_socket.shutdown(tcp::socket::shutdown_send);
}

void do_accept(yield_context yield)
{
  for (int i = 0; i < 2; ++i)
  {
    tcp_sockets.emplace_back(ioservice);
    tcp_acceptor.async_accept(tcp_sockets.back(), yield);
    spawn(ioservice, [](yield_context yield)
      { do_write(tcp_sockets.back(), yield); });
  }
}

int main()
{
  tcp_acceptor.listen();
  spawn(ioservice, do_accept);
  ioservice.run();
}

Asio boost:: Asio:: spawn()。传递的第一个参数必须是一个I/O服务对象。第二个参数是将作为协程的函数。这个函数必须接受boost::asio::yield_context类型的对象作为它的唯一参数。它必须没有返回值。例32.7使用do_accept()和do_write()作为协程。如果函数签名不同,如do_write()的情况,则必须使用std::bind或lambda函数等适配器。

Platform-specific I/O Objects

Abstract

Asio还提供了特定于平台的I/O对象,因为有些异步操作只在某些平台上可用,例如Windows或Linux。

How

目录监控

#include <boost/asio/io_service.hpp>
#include <boost/asio/windows/object_handle.hpp>
#include <boost/system/error_code.hpp>
#include <iostream>
#include <Windows.h>

using namespace boost::asio;
using namespace boost::system;

int main()
{
  io_service ioservice;

  HANDLE file_handle = CreateFileA(".", FILE_LIST_DIRECTORY,
    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
    OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);

  char buffer[1024];
  DWORD transferred;
  OVERLAPPED overlapped;
  ZeroMemory(&overlapped, sizeof(overlapped));
  overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  ReadDirectoryChangesW(file_handle, buffer, sizeof(buffer), FALSE,
    FILE_NOTIFY_CHANGE_FILE_NAME, &transferred, &overlapped, NULL);

  windows::object_handle obj_handle{ioservice, overlapped.hEvent};
  obj_handle.async_wait([&buffer, &overlapped](const error_code &ec) {
    if (!ec)
    {
      DWORD transferred;
      GetOverlappedResult(overlapped.hEvent, &overlapped, &transferred,
        FALSE);
      auto notification = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(buffer);
      std::wcout << notification->Action << '\n';
      std::streamsize size = notification->FileNameLength / sizeof(wchar_t);
      std::wcout.write(notification->FileName, size);
    }
  });

  ioservice.run();
}

这个例子中使用了I/O对象boost::asio::windows::object_handle,该对象仅在windows上可用。boost::asio::windows::object_handle,它基于windows函数RegisterWaitForSingleObject(),让你启动对象句柄的异步操作。RegisterWaitForSingleObject()接受的所有句柄都可以通过boost::asio::windows::object_handle使用。使用async_wait(),可以异步等待对象句柄的更改。

初始化boost::asio::windows::object_handle类型的对象obj_handle,使用windows函数CreateEvent()创建的对象句柄。句柄是OVERLAPPED结构的一部分,其地址传递给Windows函数ReadDirectoryChangesW()。Windows使用OVERLAPPED结构来启动异步操作。

ReadDirectoryChangesW()可用于监视目录并等待更改。要异步调用该函数,必须将OVERLAPPED结构传递给ReadDirectoryChangesW()。通过Boost报告异步操作的完成情况。Asio,事件处理程序在传递给ReadDirectoryChangesW()之前存储在OVERLAPPED结构中。这个事件处理程序随后被传递给obj_handle。当在obj_handle上调用async_wait()时,当在观察到的目录中检测到更改时,将执行处理程序。

#include <boost/asio/io_service.hpp>
#include <boost/asio/windows/overlapped_ptr.hpp>
#include <boost/system/error_code.hpp>
#include <iostream>
#include <Windows.h>

using namespace boost::asio;
using namespace boost::system;

int main()
{
  io_service ioservice;

  HANDLE file_handle = CreateFileA(".", FILE_LIST_DIRECTORY,
    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
    OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);

  error_code ec;
  auto &io_service_impl = use_service<detail::io_service_impl>(ioservice);
  io_service_impl.register_handle(file_handle, ec);

  char buffer[1024];
  auto handler = [&buffer](const error_code &ec, std::size_t) {
    if (!ec)
    {
      auto notification =
        reinterpret_cast<FILE_NOTIFY_INFORMATION*>(buffer);
      std::wcout << notification->Action << '\n';
      std::streamsize size = notification->FileNameLength / sizeof(wchar_t);
      std::wcout.write(notification->FileName, size);
    }
  };
  windows::overlapped_ptr overlapped{ioservice, handler};
  DWORD transferred;
  BOOL ok = ReadDirectoryChangesW(file_handle, buffer, sizeof(buffer),
    FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, &transferred, overlapped.get(),
    NULL);
  int last_error = GetLastError();
  if (!ok && last_error != ERROR_IO_PENDING)
  {
    error_code ec{last_error, error::get_system_category()};
    overlapped.complete(ec, 0);
  }
  else
  {
    overlapped.release();
  }

  ioservice.run();
}

boost::asio::windows::overlapped_ptr是一个I/O对象,它没有启动异步操作的成员函数。异步操作是通过将内部OVERLAPPED变量的指针传递给一个Windows函数开始的。除了一个I/O服务对象之外,boost::asio::windows::overlapped_ptr的构造函数还期望在异步操作完成时调用一个处理程序。

异步写文件

#include <boost/asio/io_service.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/asio/write.hpp>
#include <boost/system/error_code.hpp>
#include <iostream>
#include <unistd.h>

using namespace boost::asio;

int main()
{
  io_service ioservice;

  posix::stream_descriptor stream{ioservice, STDOUT_FILENO};
  auto handler = [](const boost::system::error_code&, std::size_t) {
    std::cout << ", world!\n";
  };
  async_write(stream, buffer("Hello"), handler);

  ioservice.run();
}

boost::asio::posix::stream_descriptor can be initialized with a file descriptor to start an asynchronous operation on that file descriptor. In the example, stream is linked to the file descriptor STDOUT_FILENO to write a string asynchronously to the standard output stream.

Boost::asio::posix::stream_descriptor可以用一个文件描述符初始化,以启动对该文件描述符的异步操作。在示例中,流链接到文件描述符STDOUT_FILENO以异步方式将字符串写入标准输出流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Boost.Asio是一个开源的跨平台网络编程库,它可以用于构建高效的异步I/O应用程序。以下是一些关于Boost.Asio的学习资源: 1. Boost.Asio官方文档:Boost.Asio的官方文档提供了详细的介绍和使用指南,包括教程、参考文档和示例代码。文档链接:https://www.boost.org/doc/libs/1_77_0/doc/html/boost_asio.html。 2. Boost.Asio学习指南:这是一篇由Boost.Asio的核心开发者编写的学习指南,它介绍了Boost.Asio的基本概念和使用方法,并提供了一些示例代码。指南链接:https://think-async.com/Asio/asio-1.18.1/doc/asio/overview/core.html。 3. Boost.Asio教程:这是一系列由Boost.Asio社区成员编写的教程,涵盖了从基础到高级的内容。教程链接:https://github.com/chriskohlhoff/asio/tree/master/asio/doc/tutorial。 4. Boost.Asio实战:这是一本关于使用Boost.Asio构建网络应用的书籍,它详细介绍了Boost.Asio的使用方法和实践经验,并提供了大量示例代码。书籍链接:https://www.oreilly.com/library/view/boostasio-c/9781785283079/。 希望这些资源能够帮助您学习和掌握Boost.Asio。 ### 回答2: boost.asio是一个基于C++的网络编程库,为开发人员提供了一套强大而灵活的工具来实现异步网络通信。 该库的教程涵盖了boost.asio的核心概念、基本用法和高级功能。首先,教程介绍了异步编程的概念,以及为什么应该使用异步编程来处理网络通信。然后,它讲解了boost.asio的核心组件,例如IoService、Socket和Buffer,以及如何使用它们进行网络连接和数据传输。 教程还会指导开发人员如何使用boost.asio处理不同类型的网络协议,例如TCP/IP和UDP。开发人员将学习如何创建服务器和客户端,并使用boost.asio的异步操作来处理连接和数据传输。教程还会介绍一些常见的网络编程任务,例如并发服务器和多线程编程,以及如何使用boost.asio来解决这些问题。 除了基本内容外,教程还涵盖了boost.asio的高级功能,例如SSL加密、定时器和信号处理。开发人员将学习如何使用SSL加密来保护网络通信,以及如何使用定时器来处理超时和延迟。此外,教程还会介绍如何使用信号处理来处理中断和异常情况。 总的来说,boost.asio教程为开发人员提供了一个全面的参考资料,帮助他们掌握这个强大的网络编程库。无论是初学者还是有经验的开发人员,都可以从中学习到如何使用boost.asio来构建高效可靠的网络应用程序。 ### 回答3: boost.asio是一个用于异步I/O操作的C++库。它提供了一个面向对象的接口,可以用于处理网络编程、文件I/O和串口通信等操作。boost.asio的设计目标是高效和可扩展性。 boost.asio教程是一个系统介绍boost.asio库的学习材料。该教程通常包含以下内容: 1. 引言:介绍boost.asio库的作用和特性。解释为什么选择boost.asio而不是其他库。 2. 环境配置:指导读者如何安装和配置boost.asio库。包括下载和安装boost库、配置编译器和连接器等步骤。 3. 基本概念:介绍boost.asio库的基本概念和术语。例如,异步操作、回调函数、handler等。 4. 网络编程:教授如何使用boost.asio库进行网络编程。包括创建Socket对象、建立连接、发送和接收数据等操作。 5. 文件I/O:介绍如何使用boost.asio库进行文件读写操作。教授如何打开文件、读取和写入数据等。 6. 串口通信:介绍如何使用boost.asio库进行串口通信。教授如何打开串口、发送和接收数据等。 7. 高级主题:介绍一些高级主题,例如多线程编程、定时器、SSL加密等。这些主题可以帮助读者更深入地理解和使用boost.asio库。 通过学习boost.asio教程,读者可以学会使用boost.asio库进行异步I/O操作。他们可以编写高性能的网络应用程序、文件处理程序和串口通信程序。同时,他们还能够了解到一些高级主题,从而扩展他们的技能和知识。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ym影子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值