【问题标题】:C++ Boost::asio x64 async_send fails with error 10014 (WSAEFAULT)C++ Boost::asio x64 async_send 失败并出现错误 10014 (WSAEFAULT)
【发布时间】:2018-04-17 12:42:41
【问题描述】:

我们有一个 C++ 程序,我要在 Visual Studio 2017 中移植到 x64。该程序使用 boost asio 通过 TCP 连接发送数据。该代码在 32 位中运行良好。但是当我为 x64 构建然后运行它时,async_send 失败并出现错误 10014 (WSAEFAULT),我调试了 boost asio 代码,而罪魁祸首是对 windows 方法 WSASend 的调用(在 boost\asio\detail\impl\win_iocp_socket_service_base .ipp): https://msdn.microsoft.com/en-us/library/windows/desktop/ms742203(v=vs.85).aspx

这是我当前失败的相关代码(已简化以排除其他可能的原因)。 此时连接建立成功,我尝试通过连接发送第一个数据:

std::vector<unsigned char> testWriteBuffer(16,0);
boost::asio::async_write(m_Socket,
              boost::asio::buffer(&testWriteBuffer[0], testWriteBuffer.size()),
                                   boost::bind(&CTIPCTCPConnection::IOHandleWrite, boost::static_pointer_cast<CTIPCTCPConnection>(shared_from_this()), NextMessage->IsLowPriority(),boost::asio::placeholders::error));

m_Socket 是这样的:

boost::asio::ip::tcp::socket      m_Socket;

不确定这是否相关,这是编译器的命令行(我们使用相同的选项构建了boost库):

/GS /W4 /Zc:wchar_t /I"..\..\..\Export\Include" /I"..\Include" /I"..\..\Include" /I"..\..\..\Include" /I"..\..\..\Ref\Include" /ZI /Gm- /Od /sdl- /Fd"C:\Workspaces\grpMiddleware\gc_AsioCom_x64\AsioCommunication\Test\Vc150\Debug_x64\\Test.pdb" /Zc:inline /fp:precise /Zp1 /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_WIN32_WINNT=0X603" /D "WINVER=0X603" /D "_MBCS" /D "_CRT_SECURE_NO_WARNINGS" /D "_TOKHEIM_FUELPOS" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /FC /Fa"C:\Workspaces\grpMiddleware\gc_AsioCom_x64\AsioCommunication\Test\Vc150\Debug_x64\\" /EHsc /nologo /Fo"C:\Workspaces\grpMiddleware\gc_AsioCom_x64\AsioCommunication\Test\Vc150\Debug_x64\\" /Fp"C:\Workspaces\grpMiddleware\gc_AsioCom_x64\AsioCommunication\Test\Vc150\Debug_x64\\Testd.pch" /diagnostics:classic 

【问题讨论】:

标签: c++ boost boost-asio


【解决方案1】:

看你发布的几行似乎有点糟糕的是,std::vector&lt;unsigned char&gt; testWriteBuffer(16,0) 很可能存在于堆栈中,因此在你调用async_write 后被销毁,但它应该在完成例程运行之前一直存在。正如您在boost::asio::buffer的文档中看到的那样

应用程序有责任确保内存区域保持有效,直到不再需要 I/O 操作。

更新

是的,WSABUF 遭受/Zp1 的困扰,请看这个简单的例子:

//#pragma pack(push, 1)
#include <Winsock2.h>

#include <cstdio>

int main(int argc, char** argv)
{
    WSABUF buffer;
    printf("size - %zu, offset of buf - %zu, offset of len - %zu", sizeof(buffer), offsetof(decltype(buffer), buf), offsetof(decltype(buffer), len));
    return 0;
}

没有它提供的包 - size - 16, offset of buf - 8, offset of len - 0, 在 x64 上使用 -size - 12, offset of buf - 4, offset of len - 0。你不能在没有/Zp1的情况下隔离boost i/o部分并编译boost吗?

【讨论】:

  • 是的,这是真的。我这样做是为了简化代码(原始代码使用共享指针正确执行此操作)。但这并不重要,因为代码甚至在向量超出范围之前就失败了。
  • @GertCorthout,是的,/Zp1 影响WSABUF,你不能隔离 i/o 代码以在没有它的情况下编译 boost 吗?
  • 感谢您的发言。一些额外的搜索发现了这种类型的错误报告给 MS:developercommunity.visualstudio.com/content/problem/194354/… 我们将使用:#pragma pack(push, 1) STRUCT DEFINTION #pragma pack(pop) 围绕我们序列化和发送的数据定义出来。
  • 是的,这是在需要对齐的结构周围使用这些编译指示的常用方法。我会说在整个项目中使用/Zp1 似乎很奇怪。
  • 我同意,这是在大约 15 到 20 年前作为一种快速而肮脏的捷径完成的。像往常一样,这些事情迟早会回来咬你两倍。
【解决方案2】:

显然这是因为 /Zp1 编译标志(结构成员对齐)。一旦我从项目及其所有依赖项中删除它,它就会再次正常工作。不过,删除它确实会打开一个全新的蠕虫罐,但要向后兼容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-26
    • 1970-01-01
    • 2023-02-21
    • 2021-12-19
    • 2010-09-15
    • 1970-01-01
    • 2015-10-17
    • 1970-01-01
    相关资源
    最近更新 更多