【BOOST C++ 6 】通信(05 windows相关的对象 )

发布于:2022-11-27 ⋅ 阅读:(291) ⋅ 点赞:(0)

目录

一、前言

二、平台相关IO示例

1. 示例 32.8 使用 boost::asio::windows::object_handle

2 示例 32.9: 使用 boost::asio::windows::overlapped_ptr

3 示例 32.10。使用 boost::asio::posix::stream_descriptor


一、前言

        特定于平台的 I/O 对象到目前为止,本章中的所有示例都是平台无关的。所有平台都支持 I/O 对象,例如 boost::asio::steady_timer 和 boost::asio::ip::tcp::socket。但是,Boost.Asio 还提供了特定于平台的 I/O 对象,因为某些异步操作仅在某些平台上可用,例如 Windows 或 Linux。

二、平台相关IO示例

1. 示例 32.8 使用 boost::asio::windows::object_handle

#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();
}

        示例 32.8 使用 I/O 对象 boost::asio::windows::object_handle,它仅在 Windows 上可用。 boost::asio::windows::object_handle 基于 Windows 函数 RegisterWaitForSingleObject(),可让您启动对象句柄的异步操作。 RegisterWaitForSingleObject() 接受的所有句柄都可以与 boost::asio::windows::object_handle 一起使用。使用 async_wait(),可以异步等待对象句柄更改。

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

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

        运行示例 32.8 时,在您将运行示例的目录中创建一个新文件。程序将检测新文件并将消息写入标准输出流。

2 示例 32.9: 使用 boost::asio::windows::overlapped_ptr

#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();
}

        示例 32.9 使用 ReadDirectoryChangesW() 和上一个一样来监控目录。这一次,对 ReadDirectoryChangesW() 的异步调用未链接到事件句柄。该示例使用类 boost::asio::windows::overlapped_ptr,它在内部使用 OVERLAPPED 结构。 get() 检索指向内部 OVERLAPPED 结构的指针。在示例中,指针随后被传递给 ReadDirectoryChangesW()。

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

        示例 32.9 使用 boost::asio::use_service() 来获取对 I/O 服务对象 ioservice 中服务的引用。 boost::asio::use_service() 是一个函数模板。您要获取的 I/O 服务的类型必须作为模板参数传递。在示例中,传递了 boost::asio::detail::io_service_impl。这种类型的 I/O 服务最接近操作系统。在 Windows 上,boost::asio::detail::io_service_impl 使用 IOCP,在 Linux 上使用 epoll()。 boost::asio::detail::io_service_impl 是一种类型定义,在 Windows 上设置为 boost::asio::detail::win_iocp_io_service,在 Linux 上设置为 boost::asio::detail::task_io_service。

        boost::asio::detail::win_iocp_io_service 提供成员函数 register_handle() 将句柄链接到 IOCP 句柄。 register_handle() 调用 Windows 函数 CreateIoCompletionPort()。此调用是示例正常工作所必需的。 CreateFileA() 返回的句柄只有在链接到 IOCP 句柄后才能通过重叠传递到 ReadDirectoryChangesW()。

        示例 32.9 检查 ReadDirectoryChangesW() 是否失败。如果 ReadDirectoryChangesW() 失败,则会重叠调用 complete() 以完成 Boost.Asio 的异步操作。传递给 complete() 的参数将转发给处理程序。

        如果 ReadDirectoryChangesW() 成功,则调用 release()。然后异步操作处于挂起状态,仅在使用 Windows 函数 ReadDirectoryChangesW() 启动的操作完成后才会完成。

3 示例 32.10。使用 boost::asio::posix::stream_descriptor

#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();
}

        示例 32.10 为 POSIX 平台引入了一个 I/O 对象。

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


网站公告

今日签到

点亮在社区的每一天
去签到