我想获取我的程序启动的计算机的IP地址,然后能够将其发送到客户端,但我总是得到0.0.0.1而不是真实的IP地址(例如127.0.0.1) )。
我目前能够获得端口,但不能获取IP地址。
我怎样才能得到它?
最好的解决方案是能够使用sockaddr_in
获取它。这就是我目前正在做的事情:
int open_connection(char* ip, int* port)
{
int sock;
struct sockaddr_in sin;
socklen_t len;
int i;
i = 0;
len = sizeof(sin);
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return (-1);
bzero(&sin, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0)
perror("Error on bind");
if (getsockname(sock, (struct sockaddr *)&sin, &len) != 0)
perror("Error on getsockname");
strcpy(ip, inet_ntoa(sin.sin_addr)); // IP = 0.0.0.0
*port = sin.sin_port;
return (sock);
}
编辑:我知道我的思维方式错误。所以我的问题是:获取自己的IP地址的最佳方式是什么?
答案 0 :(得分:11)
当bind()
套接字为0.0.0.0时,这是套接字在调用getsockname()
时可用的唯一IP。这意味着套接字绑定到所有本地接口。为了从套接字获取特定的IP,它必须绑定到特定的IP。
无论如何,使用套接字API获取计算机的本地IP是错误的方法。常见的错误是使用gethostname()
与gethostbyname()
或getaddrinfo()
来获取本地IP列表。通常这有效,但它有一些隐藏的陷阱,可以导致虚假的信息,但人们往往忽略这一事实,或者甚至不知道它一开始(我多年不知道它,但后来我学得更好)。
相反,您确实应该使用特定于平台的API来枚举本地网络接口。这将提供更可靠的信息。 Windows有GetAdaptersInfo()
和GetAdaptersAddresses()
。其他平台有getifaddrs()
。这些将告诉您哪些本地IP可用。然后,您可以bind()
套接字到0.0.0.0以接受任何这些IP上的客户端,或bind()
到特定IP以接受仅在该IP上的客户端。
答案 1 :(得分:4)
套接字API允许您枚举分配给您的网络接口的IP地址,但如果您从路由器后面连接到Internet,它将不会告诉您“真正的IP”是什么。
了解它的唯一方法是向外面的人询问。这就像FileZilla FTP Server这样的服务器是如何做到的。它们指示您将URL配置为服务器设置中的this one之类的“ip.php”脚本,以便它可以向Internet询问其公共IP地址,以便在被动模式下使用。
您还可以考虑使用STUN这一广泛用于VoIP的协议来发现公共IP。
答案 2 :(得分:1)
您可以拨打ioctl(sock,SIOCGIFADDR,adr)
参见netdevice(7)
答案 3 :(得分:0)
在@Remy Lebeau
的回答之后,我写了一个返回当前机器地址的函数。我只在macOS High Sierra上测试了这个。
interfaec
可以是lo0
,en0
等中的任何内容。
ipVersion
可以是AF_INET
或AF_INET6
。
long int getInternalAddress(char* interface, sa_family_t ipVersion)
{
struct ifaddrs *ifaddrHead, *ifaddr;
/* int_8 */
sa_family_t family;
int n;
char *interfaceName;
if (getifaddrs(&ifaddrHead) != 0)
{
fprintf(stderr, "ifaddrs error");
}
/* iterate through address list */
for (ifaddr = ifaddrHead, n = 0; ifaddr != NULL; ifaddr = ifaddr->ifa_next, n++)
{
family = ifaddr->ifa_addr->sa_family;
interfaceName = ifaddr->ifa_name;
if (!family || family != ipVersion || strcmp(interfaceName, interface)) continue;
struct sockaddr *addr = ifaddr->ifa_addr;
struct sockaddr_in* addr_in = (struct sockaddr_in*) addr;
long int address = addr_in->sin_addr.s_addr;
freeifaddrs(ifaddrHead);
return address;
}
freeifaddrs(ifaddrHead);
return 0;
}
要使用它,
int main()
{
long int address = getInternalAddress((char*) &"en0", AF_INET);
printf("%li\n", address);
return 0;
}
我还是C的初学者,如果有什么不对请告诉我。