boost::asio::async_read() of stream_descriptor 现在返回 EOF

boost::asio::async_read() of stream_descriptor now returning EOF

今天 Ubuntu 从 14.10 升级到 15.04。现在在 boost::asio::async_read()boost::asio::posix::stream_descriptor 或 tap/tun 界面中看到不同的行为。立即调用 async_read() returns boost::asio::error::eof。如果我忽略错误并循环返回以启动新的 async_read() 它最终会在字节可用时读取,并且应用程序继续工作。

执行此变通循环的问题是应用程序现在消耗 100% 的核心,因为它处于一个紧密循环中不断重新启动对 async_read() 的调用。

这就是我的设置方式:

fd = open("/dev/net/tun", O_RDWR);
....
boost::asio::posix::stream_descriptor my_stream( io_service);
my_stream.assign(fd, ec);
...
boost::asio::async_read(my_stream, my_buffer, boost::asio::transfer_at_least(16),
    [=](const EC &error, std::size_t bytes_read)
    {
        if (error) // <- this triggers with EOF error

任何人都知道在较新的内核 (tun/tap) 或 boost 1.55 中可能发生了什么变化,导致在进行异步读取时出现文件结束错误?

Ubuntu 15.04 contains the 3.19 kernel, which has a reported regression 在 TUN/TAP 用户 API:

With kernel 3.19, a read() from a TUN/TAP file descriptor in non-blocking mode will return 0 when no data is available, rather than fail with EAGAIN.

根据文档,来自 read() should only be 0 when no message has been read and the the peer has performed an orderly shutdown. Hence, the Boost.Asio implementation 的 return 值将 0 的 return 视为对等方已关闭的指示,并完成 async_read() 错误代码为 boost::asio::error::eof:

的操作
// Read some data.
signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec);

// Check for end of stream.
if (is_stream && bytes == 0)
{
  ec = boost::asio::error::eof;
  return true;
}