除了更改路由表之外,Windows 中是否有可靠的方法来强制新创建的套接字使用特定的网络接口?据我了解,接口 IP 地址的
bind()
并不能保证这一点。
(好吧,第二次幸运..)
仅供参考,这里还有另一个问题在特定网络适配器上执行 connect() 沿着同样的路线...
Windows XP 和 Windows Server® 2003 使用弱主机模型进行发送和 所有 IPv4 接口接收和 用于发送和的强大主机模型 所有 IPv6 接口接收。你 无法配置此行为。这 下一代 TCP/IP 堆栈 Windows Vista 和 Windows Server 2008 支持强大的主机发送和 IPv4 和 IPv6 均通过以下方式接收 除了以下所有接口上的默认值 Teredo 隧道接口 Teredo 主机特定中继。
所以回答你的问题(正确地,这次)在 Windows XP 和 Windows Server 2003 IP4 中不是,但对于 IP6 是。对于 Windows Vista 和 Windows 2008 是的(某些情况除外)。
也来自 https://forums.codeguru.com/showthread.php?487139-Socket-binding-with-routing-table
在Windows上,对bind()的调用会影响 仅选择传入流量的卡, 不是传出流量。因此,在一个 在多宿主系统中运行的客户端 (即,多个接口卡), 这是选择的网络堆栈 要使用的卡,并且它使其 选择仅基于 目标 IP,这又基于 在路由表上。调用bind() 不会影响卡的选择 以任何方式。
这有关系 所谓的“弱端系统” (“弱 E/S”)模型。 Vista 更改为 强大的 E/S 模型,因此问题可能 Vista下不会出现。但一切先于 Windows 版本使用弱 E/S 型号。
对于弱 E/S 模型, 路由表决定哪张卡 用于传出流量 多宿主系统。
看看这些线程是否提供了一些 见解:
“多宿主上的本地套接字绑定 Windows XP 中的主机无法工作” http://www.codeguru.com/forum/showthread.php?t=452337
《如何将一个端口连接到指定的端口》 网卡?”位于 http://www.codeguru.com/forum/showthread.php?t=451117。 这个线程提到了 CreateIpForwardEntry() 函数,其中 (我认为)可以用来创建一个 路由表中的条目,以便所有 具有指定的传出 IP 流量 服务器通过指定的路由 适配器。
“使用 2 个以太网卡”,位于 http://www.codeguru.com/forum/showthread.php?t=448863
“多宿主上的奇怪绑定行为 系统”在 http://www.codeguru.com/forum/showthread.php?t=452368
希望有帮助!
我不确定你为什么说绑定工作不可靠。当然,我没有进行详尽的测试,但以下解决方案对我有用(Win10、Visual Studio 2019)。我需要通过特定的 NIC 发送广播消息,其中计算机上可能存在多个 NIC。在下面的代码片段中,我希望广播消息在 IP 为 .202.106 的 NIC 上发出。
总结:
`
static WSADATA wsaData;
static int ServoSendPort = 8888;
static char ServoSendNetwork[] = "192.168.202.106";
static char ServoSendBroadcast[] = "192.168.255.255";
` ... < snip >
if ( WSAStartup(MAKEWORD(2,2), &wsaData) != NO_ERROR )
return false;
// Make a UDP socket
SOCKET ServoSendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
int iOptVal = TRUE;
int iOptLen = sizeof(int);
int RetVal = setsockopt(ServoSendSocket, SOL_SOCKET, SO_BROADCAST, (char*)&iOptVal, iOptLen);
// Bind it to a particular interface
sockaddr_in ServoBindAddr={0};
ServoBindAddr.sin_family = AF_INET;
ServoBindAddr.sin_addr.s_addr = inet_addr( ServoSendNetwork ); // target NIC
ServoBindAddr.sin_port = htons( ServoSendPort );
int bindRetVal = bind( ServoSendSocket, (sockaddr*) &ServoBindAddr, sizeof(ServoBindAddr) );
if (bindRetVal == SOCKET_ERROR )
{
int ErrorCode = WSAGetLastError();
CString errMsg;
errMsg.Format ( _T("rats! bind() didn't work! Error code %d\n"), ErrorCode );
OutputDebugString( errMsg );
}
// now create the address to send to...
sockaddr_in ServoSendAddr={0};
ServoSendAddr.sin_family = AF_INET;
ServoSendAddr.sin_addr.s_addr = inet_addr( ServoSendBroadcast ); //
ServoSendAddr.sin_port = htons( ServoSendPort );
...
#define NUM_BYTES_SERVO_SEND 20
unsigned char sendBuf[NUM_BYTES_SERVO_SEND];
int BufLen = NUM_BYTES_SERVO_SEND;
ServoSocketStatus = sendto(ServoSendSocket, (char*)sendBuf, BufLen, 0, (SOCKADDR *) &ServoSendAddr, sizeof(ServoSendAddr));
if(ServoSocketStatus == SOCKET_ERROR)
{
ServoUdpSendBytes = WSAGetLastError();
CString message;
message.Format(_T("Error transmitting UDP message to Servo Controller: %d."), ServoSocketStatus);
OutputDebugString(message);
return false;
}
https://learn.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options
看这个表情:
SO_DONTROUTE
表示传出数据应在套接字绑定的任何接口上发送,而不是在其他接口上路由。该选项仅对面向消息的协议有效。 Microsoft 提供商默默地忽略此选项,并始终查阅路由表以查找适当的传出接口。
那么windows就不行了???