如何从 udp 套接字获取您自己的(本地)IP 地址(C/C++)
题
- 您有多个网络适配器。
- 将 UDP 套接字绑定到本地端口,而不指定地址。
- 在其中一个适配器上接收数据包。
如何获取接收数据包的适配器的本地 IP 地址?
问题是:“接收器适配器的IP地址是什么?”不是我们在发件人中获得的地址
receive_from( ..., &senderAddr, ... );
称呼。
解决方案
您可以枚举所有网络适配器,获取它们的 IP 地址,并将子网掩码覆盖的部分与发送者的地址进行比较。
喜欢:
IPAddress FindLocalIPAddressOfIncomingPacket( senderAddr )
{
foreach( adapter in EnumAllNetworkAdapters() )
{
adapterSubnet = adapter.subnetmask & adapter.ipaddress;
senderSubnet = adapter.subnetmask & senderAddr;
if( adapterSubnet == senderSubnet )
{
return adapter.ipaddress;
}
}
}
其他提示
你好,
我假设您已使用 INADDR_ANY 完成绑定以指定地址。
如果是这种情况,那么 INADDR_ANY 的语义是在所有接口上指定的端口上创建 UDP 套接字。套接字将获取发送到指定端口上所有接口的所有数据包。
使用此套接字发送时,将使用编号最小的接口。传出发件人的地址字段设置为所使用的第一个传出接口的 IP 地址。
第一个传出接口定义为执行 ifconfig -a 时的顺序。可能是 eth0。
HTH。
欢呼,罗布
不幸的是,当与绑定到“任何 IP”的套接字一起使用时,sendto 和 recvfrom API 调用从根本上被破坏,因为它们没有本地 IP 信息的字段。
所以你对此能做些什么?
- 您可以猜测(例如根据路由表)。
- 您可以获得本地地址列表并将单独的套接字绑定到每个本地地址。
- 您可以使用支持此信息的较新 API。这有两个部分,首先您必须使用相关套接字选项(对于 IPv4 为 ip_recvif,对于 IPv6 为 ipv6_recvif)来告诉堆栈您需要此信息。然后你必须使用不同的函数(linux和其他几个类unix系统上的recvmsg,windows上的WSArecvmsg)来接收数据包。
这些选项都不是很好。猜测有时显然会产生错误的答案。绑定单独的套接字会增加软件的复杂性,并且如果本地地址列表随着程序运行而更改,则会导致问题。较新的 API 是正确的技术解决方案,但可能会降低可移植性 (特别是看起来 WSArecvmsg 在 Windows XP 上不可用) 并且可能需要修改您正在使用的套接字包装器库。
编辑看起来我错了,MS 文档似乎具有误导性,并且 WSArecvmsg 在 Windows XP 上可用。看 https://stackoverflow.com/a/37334943/5083516
ssize_t recvfrom(int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len); ssize_t recvmsg(int socket, struct msghdr *message, int flags); [..] If address is not a null pointer and the socket is not connection-oriented, the source address of the message is filled in.
实际代码:
int nbytes = recvfrom(sock, buf, MAXBUFSIZE, MSG_WAITALL, (struct sockaddr *)&bindaddr, &addrlen);
fprintf(stdout, "Read %d bytes on local address %s\n", nbytes, inet_ntoa(bindaddr.sin_addr.s_addr));
希望这可以帮助。
尝试这个:
gethostbyname("localhost");