我正在设置一个 UDP 套接字并尝试将应该是有效的网络广播地址绑定到它(192.168.202.255 : 23456),但bind
失败并出现错误10049WSAEADDRNOTAVAIL
,. 如果我使用 localhost 广播地址 127.0.0.255,它会成功。
WSAEADDRNOTAVAIL
的文档说“请求的地址在其上下文中无效。这通常是由于尝试绑定到对本地计算机无效的地址。这也可能是由于 connect、sendto、WSAConnect、WSAJoinLeaf 或WSASendTo 当远程地址或端口对远程计算机无效时(例如,地址或端口 0)。" 但我认为这个地址 192.168.202.255 应该是一个有效的广播地址,因为运行时有以下条目ipconfig
:
可能是什么问题?
代码
我是 Winsock 编程的新手,可能犯了一个基本错误,但我找不到它。我到目前为止的代码是:
m_ulAddress = ParseIPAddress(strAddress);
// Winsock 2.2 is supported in XP
const WORD wVersionRequested = MAKEWORD(2, 2);
WSADATA oWSAData;
const int iError = WSAStartup(wVersionRequested, &oWSAData);
if (iError != 0) {
PrintLine(L"Error starting the network connection: WSAStartup error " + IntToStr(iError));
} else if (LOBYTE(oWSAData.wVersion) != 2 || HIBYTE(oWSAData.wVersion) != 2) {
PrintLine(L"Error finding version 2.2 of Winsock; got version " + IntToStr(LOBYTE(oWSAData.wVersion)) + L"." + IntToStr(HIBYTE(oWSAData.wVersion)));
} else {
m_oSocket = socket(AF_INET, SOCK_DGRAM /*UDP*/, IPPROTO_UDP);
if (m_oSocket == INVALID_SOCKET) {
PrintLine(L"Error creating the network socket");
} else {
// Socket needs to be able to send broadcast messages
int iBroadcast = true; // docs say int sized, but boolean values
if (setsockopt(m_oSocket, SOL_SOCKET, SO_BROADCAST, (const char*)&iBroadcast, sizeof(iBroadcast)) != 0) {
PrintLine(L"Error setting socket to allow broadcast addresses; error " + IntToStr(WSAGetLastError()));
} else {
m_oServer.sin_family = AF_INET;
m_oServer.sin_port = m_iPort;
m_oServer.sin_addr.S_un.S_addr = m_ulAddress;
// !!! This is the failing call
if (bind(m_oSocket, (sockaddr*)&m_oServer, sizeof(m_oServer)) == -1) {
PrintLine(L"Error binding address " + String(strAddress.c_str()) + L":" + IntToStr(m_iPort) + L" to socket; error " + IntToStr(WSAGetLastError()));
} else {
m_bInitialisedOk = true;
}
}
}
}
评论
ParseIPAddress
是一个包装器inet_addr
;检查它的价值m_oServer.sin_addr.S_un.S_addr
似乎是正确的。 m_oSocket
是一个SOCKET
。我添加了调用,setsockopt
因为默认情况下,除了 TCP 之外,您不能通过任何方式进行广播(请参阅's Remarks中的第二段sendto
);这个电话没有任何区别。 PrintLine
是控制台输出的包装器。由于我使用的是 C++ Builder 及其 VCL 库,因此奇怪String / c_str()
的转换正在与 C++ wstrings 到 VCL Unicode 字符串之间相互转换。IP 地址是一个窄 (char) 字符串。
sendto
文档指出“如果打开套接字,则进行 setsockopt 调用,然后进行 sendto 调用,Windows 套接字执行隐式绑定函数调用。” 这意味着bind
根本不需要。如果我省略了电话,那么sendto
像这样调用:
const int iLengthBytes = strMessage.length() * sizeof(char); // Narrow string
const int iSentBytes = sendto(m_oSocket, strMessage.c_str(), iLengthBytes, 0, (sockaddr*)&m_oServer, sizeof(m_oServer));
if (iSentBytes != iLengthBytes) {
PrintLine(L"Error sending network message; error: " + IntToStr(WSAGetLastError()));
失败并出现错误 10047,WSAEAFNOSUPPORT
“协议系列不支持地址系列。”
(在备注netsh winsock show catalog
底部提到socket
)的输出很长,但确实包括几个提到 UDP 和 IPv4 的条目。
一个可能的复杂情况是它在 VMWare Fusion 主机上运行。Fusion 确实有一个奇怪的网络设置。我还配置了一个 Cisco VPN 并运行回我的办公室。连接和断开连接没有区别。
对我来说似乎很狡猾的一件事是将SOCKET
m_oSocket 硬转换为sockaddr
,但是当我阅读示例时,这似乎是 Winsock 编程的正常做法。可能需要阅读它,因为底层解释取决于协议族。这似乎是一个潜在的错误来源,但我不知道如何避免它。
有任何想法吗?我很难过:)
设置
- 在 VMWare Fusion 4.1.3 上运行的 Windows 7 Pro
- 该程序使用Embarcadero C++ Builder 2010编译为 32 位。
- 该程序只是一个控制台程序