如何使用套接字地址获取自己的IP地址?
我想获取启动我的程序的计算机的IP地址,然后将其发送到客户端,但我总是得到0.0.0.1而不是真正的IP地址(例如127.0.0.1) 。如何使用套接字地址获取自己的IP地址?
我目前能够获取端口,但不是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地址的最佳方式?
当您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上的客户端。
请详细说明getaddrinfo()中的“* ... hidden gotchas ... *”吗? – alk 2013-04-10 06:20:49
'gethostbyname()'和'getaddrinfo()'旨在使用DNS查找将主机名解析为IP。他们并不是要检索有关localhost的信息。 a)用户可能改变/损坏操作系统的DNS缓存(hosts文件等),b)PC的主机名被配置为根本没有IP或映射到可能不属于所有IP的多个IP到PC(思考负载平衡等)。在所有设置中传递本地主机名时,这些函数不能100%保证返回有效的本地IP地址。像'GetAdaptersInfo()'和'getifsaddrs()'这样的函数就是为此而设计的。 – 2013-04-10 08:31:28
哦,是的,**外部** DNS涉及到的是你基本上所指的。我同意这一点。谢谢澄清。 – alk 2013-04-10 08:41:10
套接字API允许您枚举分配给您的网络接口的IP地址,但如果您从路由器后面连接到Internet,它不会告诉您“真实IP”是什么。
要知道它的唯一方法是通过询问外面的人。多数民众赞成在如FileZilla FTP服务器这样的服务器那样做。它们会指示您在服务器设置中将URL配置为“ip.php”脚本,如this one,以便它可以询问Internet的什么是公共IP地址,以便在被动模式下使用。
您也可以考虑使用STUN,一种在VoIP中广泛使用的协议来发现公共IP。
+1。如果OP需要更多选项,我个人喜欢[ifconfig.me](http://ifconfig.me)和[canhazip.com](http://canhazip.com)。 – jweyrich 2013-04-10 00:42:37
谢谢,这不符合我目前的需求(这是一个学校项目,并不意味着从互联网上工作)。我会看看我是否有时间来实施它。 – 2013-04-10 00:44:57
你可以调用的ioctl(袜子,SIOCGIFADDR,ADR)
看到netdevice(7)
继@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初学者,如果有什么错误,请告诉我。
如果客户跟你说话......他已经有自己的IP地址。我很困惑你为什么需要明确地发送它。 – Pyrce 2013-04-10 00:22:23
@Pyrce我正在做一个FTP服务器,并进入被动模式时,我需要发送的IP地址和服务器侦听端口。即使是同一个IP地址... – 2013-04-10 00:25:16
也许这老题? http://*.com/questions/212528/get-the-ip-address-of-the-machine我认为绑定到0.0.0.0是一个特定的事情,但是,这意味着绑定所有IP地址 - 我怀疑你倒是让别的了绑定的,因为这就是你的过去。 – Rup 2013-04-10 00:28:48