Linux 获取机器的IP地址
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/212528/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get the IP address of the machine
提问by BlaM
This Question is almost the same as the previously asked Get the IP Address of local computer-Question. However I need to find the IP address(es) of a Linux Machine.
这个问题和之前问的获取本地计算机的IP地址-问题几乎一样。但是我需要找到Linux Machine的 IP 地址。
So: How do I - programmatically in C++- detect the IP addresses of the linux server my application is running on. The servers will have at least two IP addresses and I need a specific one (the one in a given network (the public one)).
所以:我如何 - 在C++ 中以编程方式- 检测运行我的应用程序的 Linux 服务器的 IP 地址。服务器将至少有两个 IP 地址,我需要一个特定的地址(给定网络中的一个(公共网络))。
I'm sure there is a simple function to do that - but where?
我确定有一个简单的功能可以做到这一点 - 但在哪里?
To make things a bit clearer:
为了让事情更清楚一点:
- The server will obviously have the "localhost": 127.0.0.1
- The server will have an internal (management) IP address: 172.16.x.x
- The server will have an external (public) IP address: 80.190.x.x
- 服务器显然会有“本地主机”:127.0.0.1
- 服务器将有一个内部(管理)IP 地址:172.16.xx
- 服务器将有一个外部(公共)IP 地址:80.190.xx
I need to find the external IP address to bind my application to it. Obviously I can also bind to INADDR_ANY (and actually that's what I do at the moment). I would prefer to detect the public address, though.
我需要找到外部 IP 地址以将我的应用程序绑定到它。显然我也可以绑定到 INADDR_ANY(实际上这就是我目前所做的)。不过,我更愿意检测公共地址。
回答by Steve Baker
- Create a socket.
- Perform
ioctl(<socketfd>, SIOCGIFCONF, (struct ifconf)&buffer);
- 创建一个套接字。
- 履行
ioctl(<socketfd>, SIOCGIFCONF, (struct ifconf)&buffer);
Read /usr/include/linux/if.h
for information on the ifconf
and ifreq
structures. This should give you the IP address of each interface on the system. Also read /usr/include/linux/sockios.h
for additional ioctls.
阅读/usr/include/linux/if.h
有关ifconf
和ifreq
结构的信息。这应该为您提供系统上每个接口的 IP 地址。另请阅读/usr/include/linux/sockios.h
其他 ioctl。
回答by Steve Baker
You can do some integration with curl as something as easy as: curl www.whatismyip.org
from the shell will get you your global ip. You're kind of reliant on some external server, but you will always be if you're behind a NAT.
您可以像 curl 一样简单地与 curl 进行一些集成:curl www.whatismyip.org
从 shell 将获得您的全局 ip。您有点依赖某些外部服务器,但如果您在 NAT 后面,您将始终如此。
回答by camh
Further to what Steve Baker has said, you can find a description of the SIOCGIFCONF ioctl in the netdevice(7) man page.
除了 Steve Baker 所说的之外,您还可以在netdevice(7) 手册页中找到对 SIOCGIFCONF ioctl 的描述。
Once you have the list of all the IP addresses on the host, you will have to use application specific logic to filter out the addresses you do not want and hope you have one IP address left.
一旦您获得了主机上所有 IP 地址的列表,您将必须使用特定于应用程序的逻辑来过滤掉您不想要的地址,并希望您只剩下一个 IP 地址。
回答by jjvainio
As you have found out there is no such thing as a single "local IP address". Here's how to find out the local address that can be sent out to a specific host.
正如您发现的那样,没有单一的“本地 IP 地址”这样的东西。以下是如何找出可以发送到特定主机的本地地址。
- Create a UDP socket
- Connect the socket to an outside address (the host that will eventually receive the local address)
- Use getsockname to get the local address
- 创建 UDP 套接字
- 将套接字连接到外部地址(最终将接收本地地址的主机)
- 使用getsockname获取本地地址
回答by Twelve47
I found the ioctl solution problematic on os x (which is POSIX compliant so should be similiar to linux). However getifaddress() will let you do the same thing easily, it works fine for me on os x 10.5 and should be the same below.
我发现 ioctl 解决方案在 os x 上有问题(它符合 POSIX,所以应该类似于 linux)。但是 getifaddress() 会让你轻松地做同样的事情,它在 os x 10.5 上对我来说很好用,下面应该是一样的。
I've done a quick example below which will print all of the machine's IPv4 address, (you should also check the getifaddrs was successful ie returns 0).
我在下面做了一个快速示例,它将打印机器的所有 IPv4 地址,(您还应该检查 getifaddrs 是否成功,即返回 0)。
I've updated it show IPv6 addresses too.
我已经更新它也显示 IPv6 地址。
#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) { // check it is IP4
// is a valid IP4 Address
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) { // check it is IP6
// is a valid IP6 Address
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;
}
回答by 4dan
I like jjvainio's answer. As Zan Lnyx says, it uses the local routing table to find the IP address of the ethernet interface that would be used for a connection to a specific external host. By using a connected UDP socket, you can get the information without actually sending any packets. The approach requires that you choose a specific external host. Most of the time, any well-known public IP should do the trick. I like Google's public DNS server address 8.8.8.8 for this purpose, but there may be times you'd want to choose a different external host IP. Here is some code that illustrates the full approach.
我喜欢jjvainio 的回答。正如 Zan Lnyx 所说,它使用本地路由表来查找用于连接到特定外部主机的以太网接口的 IP 地址。通过使用连接的 UDP 套接字,您无需实际发送任何数据包即可获取信息。该方法要求您选择特定的外部主机。大多数情况下,任何知名的公共 IP 都可以解决问题。为此,我喜欢 Google 的公共 DNS 服务器地址 8.8.8.8,但有时您可能想要选择不同的外部主机 IP。下面是一些说明完整方法的代码。
void GetPrimaryIp(char* buffer, size_t buflen)
{
assert(buflen >= 16);
int sock = socket(AF_INET, SOCK_DGRAM, 0);
assert(sock != -1);
const char* kGoogleDnsIp = "8.8.8.8";
uint16_t kDnsPort = 53;
struct sockaddr_in serv;
memset(&serv, 0, sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_addr.s_addr = inet_addr(kGoogleDnsIp);
serv.sin_port = htons(kDnsPort);
int err = connect(sock, (const sockaddr*) &serv, sizeof(serv));
assert(err != -1);
sockaddr_in name;
socklen_t namelen = sizeof(name);
err = getsockname(sock, (sockaddr*) &name, &namelen);
assert(err != -1);
const char* p = inet_ntop(AF_INET, &name.sin_addr, buffer, buflen);
assert(p);
close(sock);
}
回答by Thanatos
Don't hard code it: this is the sort of thing that can change. Many programs figure out what to bind to by reading in a config file, and doing whatever that says. This way, should your program sometime in the future need to bind to something that's not a public IP, it can do so.
不要硬编码:这是可以改变的东西。许多程序通过读取配置文件来确定要绑定的内容,然后执行任何操作。这样,如果您的程序将来某个时候需要绑定到非公共 IP 的内容,它就可以这样做。
回答by Chaza
// Use a HTTP request to a well known server that echo's back the public IP address
void GetPublicIP(CString & csIP)
{
// Initialize COM
bool bInit = false;
if (SUCCEEDED(CoInitialize(NULL)))
{
// COM was initialized
bInit = true;
// Use a HTTP request to a well known server that echo's back the public IP address
void GetPublicIP(CString & csIP)
{
// Initialize COM
bool bInit = false;
if (SUCCEEDED(CoInitialize(NULL)))
{
// COM was initialized
bInit = true;
// Create a HTTP request object
MSXML2::IXMLHTTPRequestPtr HTTPRequest;
HRESULT hr = HTTPRequest.CreateInstance("MSXML2.XMLHTTP");
if (SUCCEEDED(hr))
{
// Build a request to a web site that returns the public IP address
VARIANT Async;
Async.vt = VT_BOOL;
Async.boolVal = VARIANT_FALSE;
CComBSTR ccbRequest = L"http://whatismyipaddress.com/";
// Open the request
if (SUCCEEDED(HTTPRequest->raw_open(L"GET",ccbRequest,Async)))
{
// Send the request
if (SUCCEEDED(HTTPRequest->raw_send()))
{
// Get the response
CString csRequest = HTTPRequest->GetresponseText();
// Parse the IP address
CString csMarker = "<!-- contact us before using a script to get your IP address -->";
int iPos = csRequest.Find(csMarker);
if (iPos == -1)
return;
iPos += csMarker.GetLength();
int iPos2 = csRequest.Find(csMarker,iPos);
if (iPos2 == -1)
return;
// Build the IP address
int nCount = iPos2 - iPos;
csIP = csRequest.Mid(iPos,nCount);
}
}
}
}
// Unitialize COM
if (bInit)
CoUninitialize();
}
// Create a HTTP request object
MSXML2::IXMLHTTPRequestPtr HTTPRequest;
HRESULT hr = HTTPRequest.CreateInstance("MSXML2.XMLHTTP");
if (SUCCEEDED(hr))
{
// Build a request to a web site that returns the public IP address
VARIANT Async;
Async.vt = VT_BOOL;
Async.boolVal = VARIANT_FALSE;
CComBSTR ccbRequest = L"http://whatismyipaddress.com/";
// Open the request
if (SUCCEEDED(HTTPRequest->raw_open(L"GET",ccbRequest,Async)))
{
// Send the request
if (SUCCEEDED(HTTPRequest->raw_send()))
{
// Get the response
CString csRequest = HTTPRequest->GetresponseText();
// Parse the IP address
CString csMarker = "<!-- contact us before using a script to get your IP address -->";
int iPos = csRequest.Find(csMarker);
if (iPos == -1)
return;
iPos += csMarker.GetLength();
int iPos2 = csRequest.Find(csMarker,iPos);
if (iPos2 == -1)
return;
// Build the IP address
int nCount = iPos2 - iPos;
csIP = csRequest.Mid(iPos,nCount);
}
}
}
}
// Unitialize COM
if (bInit)
CoUninitialize();
}
回答by Erik Aronesty
This has the advantage of working on many flavors of unix ...and you can modify it trivially to work on any o/s. All of the solutions above give me compiler errors depending on the phase of the moon. The moment there's a good POSIX way to do it... don't use this (at the time this was written, that wasn't the case).
这具有在多种 unix 上工作的优势……您可以对其进行微不足道的修改以在任何操作系统上工作。上面的所有解决方案都会根据月相给我编译器错误。现在有一种很好的 POSIX 方法来做到这一点......不要使用它(在撰写本文时,情况并非如此)。
// ifconfig | perl -ne 'print "\n" if /inet addr:([\d.]+)/'
#include <stdlib.h>
int main() {
setenv("LANG","C",1);
FILE * fp = popen("ifconfig", "r");
if (fp) {
char *p=NULL, *e; size_t n;
while ((getline(&p, &n, fp) > 0) && p) {
if (p = strstr(p, "inet ")) {
p+=5;
if (p = strchr(p, ':')) {
++p;
if (e = strchr(p, ' ')) {
*e='##代码##';
printf("%s\n", p);
}
}
}
}
}
pclose(fp);
return 0;
}
回答by Dave Sieving
An elegant scripted solution for Linux can be found at: http://www.damnsmalllinux.org/f/topic-3-23-17031-0.html
可以在以下位置找到适用于 Linux 的优雅脚本解决方案:http: //www.damnsmalllinux.org/f/topic-3-23-17031-0.html