如何获取收到数据包的适配器的本地IP地址?
问题是,“接收器适配器的IP地址是多少?”不是我们在
中获得的发件人地址receive_from( ..., &senderAddr, ... );
呼叫。
答案 0 :(得分:3)
您可以枚举所有网络适配器,获取其IP地址,并将子网掩码所涵盖的部分与发件人的地址进行比较。
像:
IPAddress FindLocalIPAddressOfIncomingPacket( senderAddr )
{
foreach( adapter in EnumAllNetworkAdapters() )
{
adapterSubnet = adapter.subnetmask & adapter.ipaddress;
senderSubnet = adapter.subnetmask & senderAddr;
if( adapterSubnet == senderSubnet )
{
return adapter.ipaddress;
}
}
}
答案 1 :(得分:3)
天儿真好,
我假设您已使用INADDR_ANY完成绑定以指定地址。
如果是这种情况,那么INADDR_ANY的语义就是在所有接口上指定的端口上创建UDP套接字。套接字将把所有数据包发送到指定端口上的所有接口。
使用此套接字发送时,使用编号最小的接口。传出发件人的地址字段设置为使用的第一个传出接口的IP地址。
第一个传出接口定义为执行ifconfig -a时的序列。它可能是eth0。
HTH。
欢呼声, 罗布
答案 2 :(得分:3)
timbo提供的解决方案假定地址范围是唯一的且不重叠。虽然情况通常如此,但它不是一般解决方案。
有一个很好的函数实现,它完全符合你在Steven的书“Unix网络编程”(第20.2节)中提供的功能。 这是一个基于recvmsg()的函数,而不是recvfrom()。如果您的套接字启用了IP_RECVIF选项,则recvmsg()将返回接收数据包的接口的索引。然后可以使用它来查找目标地址。
源代码可用here。有问题的函数是'recvfrom_flags()'
答案 3 :(得分:0)
不幸的是,当使用绑定到"任何IP"的套接字时,sendto和recvfrom API调用基本上被破坏了。因为他们没有本地IP信息的字段。
那么你能做些什么呢?
这些选项都不是很好。猜测显然会产生错误的答案。绑定单独的套接字会增加软件的复杂性,如果本地地址列表发生更改,程序将运行,则会导致问题。较新的API是正确的技术解决方案但可能会降低可移植性(特别是它看起来像Windows XP上没有WSArecvmsg)并且可能需要修改您正在使用的套接字包装器库。
编辑看起来我错了,似乎MS文档有误导性,并且Windows XP上提供了WSArecvmsg。见https://stackoverflow.com/a/37334943/5083516
答案 4 :(得分:0)
您可以先将SO_REUSEADDR设置为true
BOOL bOptVal = 1;
setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&boOptVal, sizeof(bOptVal));
在receive_from( ..., &remoteAddr, ... );
之后创建另一个套接字,然后重新连接到remoteAddr。然后调用getsockname可以获取IP地址。
SOCKET skNew = socket( )
// Same local address and port as that of your first socket
// INADDR_ANY
bind(skNew, , )
// set SO_REUSEADDR to true again
setsockopt(skNew, SOL_SOCKET, SO_REUSEADDR, (char *)&boOptVal, sizeof(bOptVal));
// connect back
connect(skNew, remoteAddr)
// get local address of the socket
getsocketname(skNew, )
答案 5 :(得分:-3)
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));
希望这会有所帮助。
答案 6 :(得分:-3)
试试这个:
gethostbyname("localhost");