Winsock 连接失败并显示 WSAEFAULT |仅在 Windows 11 上出现错误
Posted
技术标签:
【中文标题】Winsock 连接失败并显示 WSAEFAULT |仅在 Windows 11 上出现错误【英文标题】:Winsock connect fails with WSAEFAULT | Error on Windows 11 only 【发布时间】:2021-12-19 17:14:07 【问题描述】:我的代码在从 XP 到 10 的任何 Windows 上都能完美运行。 现在我在Win11中第一次测试了我的代码, 并且 connect() 函数失败并出现错误 10014 WSAEFAULT:
地址错误。 系统在尝试使用调用的指针参数时检测到无效的指针地址。如果应用程序传递了无效的指针值,或者缓冲区的长度太小,则会发生此错误。例如,如果参数的长度(即 sockaddr 结构)小于 sizeof(sockaddr)。
但是,当我使用调试器检查时,sockaddr_in 结构似乎传递正确:
connect(hSocket, (sockaddr*)(&InSockAddr), sizeof(InSockAddr))
我正在使用 Visual C++ 2015 编译器。
以下是相关代码的片段:
#include <WinSock2.h>
class CConnection
public:
static bool bWinsockInitialized;
SOCKET hSocket = INVALID_SOCKET;
sockaddr_in sockAddr;
bool Create();
bool InitializeWinsock();
bool Connect(sockaddr_in &InSockAddr);
;
CConnection sckt_Main;
sockaddr_in g_sockAddr;
void main()
if (!sckt_Main.Create())
// Error: Unable to create connection socket
return;
g_sockAddr.sin_family = AF_INET;
// Get IP address from string.
// If address is a DNS, HostInfo->h_addr will contain resolved IP address.
// Save host information into HostInfo struct:
hostent* HostInfo = gethostbyname("127.0.0.1");
//Error checking:
if (!HostInfo)
return;
assert((sizeof(g_sockAddr.sin_addr)) >= HostInfo->h_length);
//Copy the resolved IP address into our sockAddr structure:
memcpy(&g_sockAddr.sin_addr, HostInfo->h_addr, HostInfo->h_length);
//Saves connection port
g_sockAddr.sin_port = htons(atoi("2405"));
sckt_Main.Connect(g_sockAddr);
bool CConnection::Create()
if (!InitializeWinsock())
return false;
hSocket = socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
if (this->hSocket == INVALID_SOCKET)
return false;
return true;
bool CConnection::InitializeWinsock()
WSADATA wsaData;
if (!WSAStartup(MAKEWORD(2, 2), &wsaData))
bWinsockInitialized = true;
else bWinsockInitialized = false;
return bWinsockInitialized;
bool CConnection::Connect(sockaddr_in &InSockAddr)
// If no error occurs, connect returns zero.
// Otherwise, it returns SOCKET_ERROR, and a specific error code can be retrieved by calling WSAGetLastError.
if (connect(hSocket, (sockaddr*)(&InSockAddr), sizeof(InSockAddr)) == 0)
// Connect SUCCESS
return true;
else
// !!! connect error !!!
int err = WSAGetLastError();
return false;
【问题讨论】:
你有一个缓冲区溢出。试试assert((sizeof (g_sockAddr.sin_addr)) >= HostInfo->h_length)
。
对atoi
的调用也毫无意义。要么它是一个常量,在这种情况下使用数字文字而不是字符串,要么它是一个只有在运行时才知道值的字符串,在这种情况下使用像strtol
这样的合格转换函数。
@Flavio:这可能不会导致您今天的错误,但是当您从gethostbyname()
获取 IPv6 地址时,您的代码将失败,并将顺序从 IPv4-first 更改为 IPv6-first 是正是操作系统更新所期望的那种变化。
清除 last-error 值以确保 WSAEFAULT 来自 connect
而不是来自以前的某个函数可能也是值得的。
socket(AF_UNSPEC, ...)
无效。您必须指定 AF_INET
(IPv4) 或 AF_INET6
(IPv6)。如果你想要一个同时支持 IPv4 和 IPv6 的套接字,你需要创建一个dual-stack socket,即关闭IPV6_V6ONLY
选项的AF_INET6
套接字。
【参考方案1】:
如 cmets 中所述,您的代码不支持 IPv6。 Windows 11 默认启用 IPv6。
您应该将您的代码更新为与 IPv4 与 IPv6 无关。
见Microsoft Docs。
注意微软很久以前就停止提供checkv4.exe
,但如果我根据你的代码运行它,我会得到:
sockaddr_in : use sockaddr_storage instead, or use sockaddr_in6 in addition for IPv6 support
AF_INET : use AF_INET6 in addition for IPv6 support
gethostbyname : use getaddrinfo instead
hostent : use addrinfo instead
【讨论】:
根据您的建议,我将已弃用的gethostbyname()
替换为 getaddrinfo()
。随后我编辑connect()
以从addrinfo
获取值,这样:connect(hSocket, AddrInfo->ai_addr, AddrInfo->ai_addrlen)
。现在代码可以正常工作,从 WinXP 到 Win11。谢谢。
按照 Microsoft 文档,在 getaddrinfo()
之后,我还编辑了 socket()
函数以从 addrinfo
获取地址族,而不是使用 AF_UNSPEC
。这也是解决错误的关键部分。以上是关于Winsock 连接失败并显示 WSAEFAULT |仅在 Windows 11 上出现错误的主要内容,如果未能解决你的问题,请参考以下文章
windows winsock2 socket从WSAGetLastError返回10014 WSAEFAULT(ipv4 / ipv6相关)