C - 获取外部 IP 地址
Posted
技术标签:
【中文标题】C - 获取外部 IP 地址【英文标题】:C - Get External IP Address 【发布时间】:2020-12-17 20:51:45 【问题描述】:我需要通过 C/C++ 调用获取我的公共 IP 地址。我知道作为替代方案,我可以从“http://whatismyip.akamai.com”等外部链接获得
我编写了一个示例来获取外部 IP 地址。但是我的程序没有返回外部 IP 地址。我正在获取内部 IP 地址。我在这里有什么遗漏吗?
如果不能通过这种方式,我可以读取DNS并获取IP地址吗?或者有什么方法可以使用 C API 以编程方式获取外部 IP 地址(不是通过访问某些网站)?
#include <stdio.h>
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
int main (int argc, const char * argv[])
struct ifaddrs * ifAddrStruct=NULL;
struct ifaddrs * ifa=NULL;
void * tmpAddrPtr=NULL;
getifaddrs(&ifAddrStruct);
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next)
if (!ifa->ifa_addr)
continue;
if (ifa->ifa_addr->sa_family == AF_INET)
tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
char addressBuffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
else if (ifa->ifa_addr->sa_family == AF_INET6)
tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
char addressBuffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
return 0;
注意:我确实有外部 IP 地址,我可以在运行时获取它 卷曲http://whatismyip.akamai.com
【问题讨论】:
几乎别无选择,只能求助于一些外部资源。典型的家用路由器会进行网络地址转换 (NAT),以便房子中的所有计算机共享一个向外的 IP 地址。相当多的 ISP 会自己进行二级网络地址转换,因此仅从路由器获取外向地址也不一定能给出正确答案。 你需要在路由器上运行这个程序 :) 【参考方案1】:“外部IP”是网络的属性;不是连接到网络的计算机的财产。因此,您无法调用任何函数来从标准库或操作系统中获取此类信息,因为系统不知道这些信息。
我写了一个示例来获取外部 IP 地址。
您编写了一个获取网络接口 IP 地址的程序。如果接口连接到公共网络,则 IP 是外部的。如果接口连接到专用网络,则 IP 是内部的。
通过专用网络获取外部 IP 的一种解决方案是连接到外部服务,该服务可以查看请求来自的 IP。你似乎已经知道了。
不需要外部连接的更高级的方法是在路由器系统上运行类似的服务。正如评论中所指出的,UPnP 或更具体地说,IGD 是路由器可能提供的此类服务。没有 C++ 标准和 POSIX 提供的标准 UPnP 客户端。
【讨论】:
如果网络路由器支持 uPNP 并已启用,您可以直接查询路由器的属性并发现面向公众的 WAN IP。但是,正如 Jerry Coffin 评论的那样,这可能还不够好。因此,最好查询外部来源。 @RemyLebeau 感谢您的指出。我在答案中添加了一些额外的信息。【参考方案2】:如果您获得的是内部 IP 地址,那么公共 IP 地址可能不是您计算机的财产。
大多数计算机都在进行网络地址转换的路由器后面,因此它们没有公共 IP。
UPNP 是路由器可以向 NAT 客户端提供公共 IP 地址的一种方法。您可能可以使用 UPNP 来获取您的公共 IP。
一些 IPV6 路由器会提供 IPV6 地址,您的计算机可以通过公共互联网访问。
查询外部来源将为您提供请求似乎来自的地址,这可能是您的公共地址(或者您可能在代理或 *** 后面)
哪个最好取决于你想用它做什么。
【讨论】:
【参考方案3】:您编写的代码获取本地计算机上网络接口的 IP 地址。它们与您的外部 IP 地址无关,如果您位于一层或多层 NAT 之后,它实际上驻留在具有直接 Internet 连接的路由器上。
您提到的服务的工作方式是因为当您与它们建立连接时,它们可以看到您的外部 IP 是什么,然后可以将其发送回给您。
这是连接到您列出的服务以取回 IP 的快速而肮脏的方法:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
int main(void)
struct addrinfo hints = 0, *addrs;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
int rval = getaddrinfo("whatismyip.akamai.com", "80", &hints, &addrs);
if (rval != 0)
fprintf(stderr,"getaddrinfo failed: %s\n", gai_strerror(rval));
return 1;
int s = socket(addrs->ai_family, addrs->ai_socktype, addrs->ai_protocol);
if (s == -1)
perror("socket failed");
return 1;
rval = connect(s, addrs->ai_addr, addrs->ai_addrlen);
if (rval == -1)
perror("connect failed");
return 1;
char cmd[] = "GET / HTTP/1.1\nHost: whatismyip.akamai.com\n\n";
rval = send(s, cmd, strlen(cmd), 0);
if (rval == -1)
perror("send failed");
return 1;
char buf[1000] = 0;
rval = recv(s, buf, sizeof(buf), 0);
if (rval == -1)
perror("recv failed");
return 1;
printf("response: %s\n", buf);
char *start = buf, *end;
end = strchr(start, '\n');
if (!strncmp(start, "HTTP/1.1 200 OK", end - start - 1))
while (!(end[1] == '\r' && end[2] == '\n'))
start = end + 2;
end = strchr(start, '\n');
start = end + 3;
end = strchr(start, '\n');
if (end) *end = 0;
printf("my IP: %s\n", start);
else
printf("request failed\n");
close(s);
freeaddrinfo(addrs);
return 0;
请注意,这并没有实现完整的 HTTP 客户端,并对响应的外观做了一些假设,但足以让您入门。
另一种选择是,您可以改用 int fd = popen("curl http://whatismyip.akamai.com", "r");
在单独的进程中运行 curl 并通过管道读取其输出。
【讨论】:
以上是关于C - 获取外部 IP 地址的主要内容,如果未能解决你的问题,请参考以下文章
Qt 使用 QNetworkReply 获取外部 IP 地址