提问人:thulke 提问时间:6/24/2020 最后编辑:thulke 更新时间:6/26/2020 访问量:226
Boost Asio tcp::iostream 构造在每次使用时引发访问冲突异常
Boost Asio tcp::iostream construction raise an Access Violation Exception on every second use
问:
我正在尝试使用上面提供的实现。我的代码几乎一行一行地复制了 Boost Asio 文档中发布的示例:std::iostream
boost::asio
boost::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.hpp
stream
我对调试器报告的异常的此位置的准确性没有很高的信心。由于某种原因,堆栈接缝被弄乱了,只显示一帧。
如果声明 of 被移出循环,则不会再引发异常,但随后我需要在循环结束时引发异常,否则除了来自第一个客户端连接的数据外,标准输出上不会显示任何异常。stream
stream.close()
基本上,一旦我尝试实例化多个(不一定同时),就会引发异常。boost::asio::tcp::iostream
我在 linux 下尝试了完全相同的代码(Arch linux、最新版本的 g++、相同版本的 Boost),一切正常。
我可以通过不使用 s 来解决此问题,但我的想法是将 tcp 套接字上接收的数据馈送到仅接受 的实现的解析器,因此我仍然需要将 asio 的 tcp 套接字包装在自制的(和平庸的)实现中。iostream
std::iostream
std::iostream
有没有人知道这个设置有什么问题,如果我错过了关键的某个地方或任何东西?#define
更新:
随后的调查显示,发生访问冲突的唯一情况是从 Visual Studio 中运行可执行文件(典型值,来自菜单“调试”->“启动调试”)。
构建过程似乎没有效果(直接调用 、 using 、 using )。cl.exe
MSBuild
devenv.exe
此外,如果可执行文件是从命令提示符运行的,并且只有附加调试器,则不会发生访问冲突。
此时,问题很可能与代码本身无关。
答:
好吧,在 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 是不够的,对吧)
评论
tcp::socket;
tcp::socket;
boost::asio::basic_stream_socket<boost::asio::ip::tcp>