Boost Asio tcp::iostream 构造在每次使用时引发访问冲突异常

Boost Asio tcp::iostream construction raise an Access Violation Exception on every second use

提问人:thulke 提问时间:6/24/2020 最后编辑:thulke 更新时间:6/26/2020 访问量:226

问:

我正在尝试使用上面提供的实现。我的代码几乎一行一行地复制了 Boost Asio 文档中发布的示例:std::iostreamboost::asioboost::asio::ip::tcp::socket

#include <iostream>
#include <stdexcept>

#include <boost/asio.hpp>

int main()
{
    using boost::asio::ip::tcp;
    try
    {
        boost::asio::io_service io_service;
        tcp::endpoint endpoint(tcp::v4(), 8000);
        tcp::acceptor acceptor(io_service, endpoint);

        for (;;)
        {
            tcp::iostream stream;  // <-- The exception is triggered on this line, on the second loop iteration.
            boost::system::error_code error_code;
            acceptor.accept(*stream.rdbuf(), error_code);
            std::cout << stream.rdbuf() << std::flush;
        }
    }
    catch (std::exception& exception)
    {
        std::cerr << exception.what() << std::endl;
    }

    return 0;
}

唯一的区别是我对结果的使用:我将收到的所有内容转发到标准输出。tcp::iostream

当我使用 VisualStudio2019/toolset v142 和 NuGet boost-vc142 中的 Boost 编译此代码时,仅在函数的 for 循环的第二次迭代中出现访问冲突异常

template <typename Service>
Service& service_registry::use_service(io_context& owner)
{
  execution_context::service::key key;
  init_key<Service>(key, 0);
  factory_type factory = &service_registry::create<Service, io_context>;
  return *static_cast<Service*>(do_use_service(key, factory, &owner));
} // <-- The debugger show the exception was raised on this line

在。因此,第一次迭代一切都按计划进行,连接被接受,数据显示在标准输出上,一旦第二次在堆栈上实例化,异常就会弹出。asio/detail/impl/service_registry.hppstream

我对调试器报告的异常的此位置的准确性没有很高的信心。由于某种原因,堆栈接缝被弄乱了,只显示一帧。

如果声明 of 被移出循环,则不会再引发异常,但随后我需要在循环结束时引发异常,否则除了来自第一个客户端连接的数据外,标准输出上不会显示任何异常。streamstream.close()

基本上,一旦我尝试实例化多个(不一定同时),就会引发异常。boost::asio::tcp::iostream

我在 linux 下尝试了完全相同的代码(Arch linux、最新版本的 g++、相同版本的 Boost),一切正常。

我可以通过不使用 s 来解决此问题,但我的想法是将 tcp 套接字上接收的数据馈送到仅接受 的实现的解析器,因此我仍然需要将 asio 的 tcp 套接字包装在自制的(和平庸的)实现中。iostreamstd::iostreamstd::iostream

有没有人知道这个设置有什么问题,如果我错过了关键的某个地方或任何东西?#define

更新:

随后的调查显示,发生访问冲突的唯一情况是从 Visual Studio 中运行可执行文件(典型值,来自菜单“调试”->“启动调试”)。

构建过程似乎没有效果(直接调用 、 using 、 using )。cl.exeMSBuilddevenv.exe

此外,如果可执行文件是从命令提示符运行的,并且只有附加调试器,则不会发生访问冲突。

此时,问题很可能与代码本身无关。

套接字 visual-c++ boost iostream asio

评论

0赞 sehe 6/25/2020
是真正的代码吗?这有什么作用?tcp::socket;
0赞 thulke 6/25/2020
是的,是一个有效的语句,但它不执行任何操作(它是一种解析为 )的类型。为了清楚起见,我编辑了这个问题以删除它。tcp::socket;boost::asio::basic_stream_socket<boost::asio::ip::tcp>
0赞 sehe 6/25/2020
我从不怀疑这是一个有效的声明。我甚至设法在 Windows 上进行了测试,并发布了我的发现。[我可以确认,即使如此,杂散线也没有影响。

答:

1赞 sehe 6/25/2020 #1

好吧,在 Windows 上测试它非常痛苦。

当然,我首先在 Linux (clang/gcc) 和 Windows 上的 MingW 8.1 上尝试。

然后,我咬紧牙关,跳了一大圈,在命令行中使用 boost 包¹ 获取 MSVC。

我通过手动将 boost_{system,date_time,regex} 的 .lib/.dll 复制到工作目录中来作弊,因此命令行保持“wieldy”:

C:\work>C:\Users\sghee\Downloads\nuget.exe install boost_system-vc142
C:\work>C:\Users\sghee\Downloads\nuget.exe install boost_date_time-vc142
C:\work>C:\Users\sghee\Downloads\nuget.exe install boost_regex-vc142

(一定要在这段时间喝点咖啡)

C:\work\> cl /EHsc test.cpp /I .\boost.1.72.0.0\lib\native\include /link

现在我可以运行test.exe了

C:\work\> test.exe

它听得很好,接受连接(顺序,而不是同时)。如果在第一个客户端仍处于连接状态时连接第二个客户端,则该客户端将排队,并且仅在第一个客户端断开连接后才被接受。这很好,因为这是您对同步和循环的期望。accept

我使用Ncat.exe(来自Nmap)进行连接:

 C:\Program Files (x86)\Nmap>.\ncat.exe localhost 8000

怪癖:MSVC cl.exe 构建(行向)的缓冲很好,而不是 MingW 行为,即使 MingW 也使用 ws2_32.dll。#trivia

我知道这没有“帮助”,但也许您可以比较笔记并查看您的系统有什么不同。

测试视频


¹(如果没有 VS,这是一项艰巨的工作,而且我 - 显然 - 空间不足,因为 VM 的 50GiB 是不够的,对吧)

评论

0赞 sehe 6/25/2020
在我的 Win10 VM 中添加了测试的 gif
0赞 thulke 6/26/2020
好的,所以我们在这里进入了奇怪的领域。我可以复制您的步骤,结果相同:没有访问冲突。但实际上,我获得访问冲突的唯一方法是当我在附加调试器的 Visual Studio 中运行可执行文件时。如果我在外部运行它,然后才附加调试器,则不会发生访问冲突。因此,该问题很可能与 VS 有关,而不是其他任何事情。