我有一个代码来获取本地IP地址。这是我使用的代码。
typedef std::map<string,string> settings_t;
void loadLocalIp (settings_t &ipConfig)
{
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->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);
string key(ifa->ifa_name);
string value(addressBuffer);
cout<<key<<" =1 " <<value<<endl;
ipConfig.insert(std::pair<string,string>(key, value));
// printf("'%s': %s\n", ifa->ifa_name, addressBuffer);
}
}
if (ifAddrStruct!=NULL)
freeifaddrs(ifAddrStruct);//remember to free ifAddrStruct
}
int main()
{
settings_t ipConfig;
loadLocalIp(ipConfig);
cout<<ipConfig.at("enp2s0")<<endl;
return 0;
}
所以我的结果是
lo =1 127.0.0.1
enp2s0 =1 172.20.55.6
172.20.55.6
但在另一台计算机中,界面名称不同。他们得到的结果如下,
lo =1 127.0.0.1
ens32 =1 172.20.55.9
terminate called after throwing an instance of 'std::out_of_range'
what(): map::at
Aborted (core dumped)
无论接口名称是什么,我想获取我的IP地址。如果接口名称因计算机而异,如何获取本地IP地址。无论接口名称是什么,它都应该给出ip地址。我怎么能这样做?
我的问题是,现在我从这个方法获取本地IP。但无论接口名称是什么,我都应该获得IP。有一件事,我需要找到接口名称并将其应用于我的上述代码(或)是否有任何其他选项来找到没有该接口的IP?
答案 0 :(得分:4)
无论接口名称是什么,我都想获取我的IP地址。
通过查看网络接口很难可靠地获取本地IP地址。正如您已经发现的那样,网络接口名称对于您运行的每个主机都是唯一的。更复杂的是,计算机可能有多个网络接口,每个网络接口可能连接也可能没有连接到互联网。
您无需使用默认界面。更简单的方法是让OS路由表为您解决问题。您可以通过设置到某个外部服务器的套接字连接然后调用getsockname
来获取本地地址来完成此操作。此示例使用8.8.8.8
处的Google DNS服务器建立套接字连接,但您可以使用您喜欢的任何外部服务器。
#include <iostream> ///< cout
#include <cstring> ///< memset
#include <errno.h> ///< errno
#include <sys/socket.h> ///< socket
#include <netinet/in.h> ///< sockaddr_in
#include <arpa/inet.h> ///< getsockname
#include <unistd.h> ///< close
int main()
{
const char* google_dns_server = "8.8.8.8";
int dns_port = 53;
struct sockaddr_in serv;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
//Socket could not be created
if(sock < 0)
{
std::cout << "Socket error" << std::endl;
}
memset(&serv, 0, sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_addr.s_addr = inet_addr(google_dns_server);
serv.sin_port = htons(dns_port);
int err = connect(sock, (const struct sockaddr*)&serv, sizeof(serv));
if (err < 0)
{
std::cout << "Error number: " << errno
<< ". Error message: " << strerror(errno) << std::endl;
}
struct sockaddr_in name;
socklen_t namelen = sizeof(name);
err = getsockname(sock, (struct sockaddr*)&name, &namelen);
char buffer[80];
const char* p = inet_ntop(AF_INET, &name.sin_addr, buffer, 80);
if(p != NULL)
{
std::cout << "Local IP address is: " << buffer << std::endl;
}
else
{
std::cout << "Error number: " << errno
<< ". Error message: " << strerror(errno) << std::endl;
}
close(sock);
return 0;
}
答案 1 :(得分:1)
这些答案似乎都不够好:在界面上行走时遇到太多麻烦,或者需要连接到Internet。
这是一种基于贾斯汀·兰德尔的answer的方法。基本相同,但是连接到环回地址127.0.0.1,因此不需要连接到WWW。
在connect(3)的POSIX man页上:
如果套接字尚未绑定到本地地址,则connect()必须将其绑定到一个地址,除非套接字的地址族是AF_UNIX,否则该地址是未使用的本地地址。
因为它不需要连接到远程服务器,所以几乎没有开销。
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
int main(void) {
int sock = socket(PF_INET, SOCK_DGRAM, 0);
sockaddr_in loopback;
if (sock == -1) {
std::cerr << "Could not socket\n";
return 1;
}
std::memset(&loopback, 0, sizeof(loopback));
loopback.sin_family = AF_INET;
loopback.sin_addr.s_addr = INADDR_LOOPBACK; // using loopback ip address
loopback.sin_port = htons(9); // using debug port
if (connect(sock, reinterpret_cast<sockaddr*>(&loopback), sizeof(loopback)) == -1) {
close(sock);
std::cerr << "Could not connect\n";
return 1;
}
socklen_t addrlen = sizeof(loopback);
if (getsockname(sock, reinterpret_cast<sockaddr*>(&loopback), &addrlen) == -1) {
close(sock);
std::cerr << "Could not getsockname\n";
return 1;
}
close(sock);
char buf[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, &loopback.sin_addr, buf, INET_ADDRSTRLEN) == 0x0) {
std::cerr << "Could not inet_ntop\n";
return 1;
} else {
std::cout << "Local ip address: " << buf << "\n";
}
}
答案 2 :(得分:0)
感谢您的解决方案。它工作正常。但是当我搜索解决方案时,我也提出了以下答案。请看一下。这个答案的优点和缺点是什么。
FILE *f;
char line[100] , *p , *c;
f = fopen("/proc/net/route" , "r");
while(fgets(line , 100 , f))
{
p = strtok(line , " \t");
c = strtok(NULL , " \t");
if(p!=NULL && c!=NULL)
{
if(strcmp(c , "00000000") == 0)
{
printf("Default interface is : %s \n" , p);
break;
}
}
}
//which family do we require , AF_INET or AF_INET6
int fm = AF_INET;
struct ifaddrs *ifaddr, *ifa;
int family , s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1)
{
perror("getifaddrs");
exit(EXIT_FAILURE);
}
//Walk through linked list, maintaining head pointer so we can free list later
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL)
{
continue;
}
family = ifa->ifa_addr->sa_family;
if(strcmp( ifa->ifa_name , p) == 0)
{
if (family == fm)
{
s = getnameinfo( ifa->ifa_addr, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6) , host , NI_MAXHOST , NULL , 0 , NI_NUMERICHOST);
if (s != 0)
{
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("address: %s", host);
}
printf("\n");
}
}
freeifaddrs(ifaddr);
return 0;
答案 3 :(得分:0)
获取本地ip的一种很酷的方法是执行ipconfig命令,将输出保存到一个文件中以进行读取,然后解析数据,以便输出仅显示您的ipv4地址。 可以通过以下方式完成:
std::string GetParsedIPConfigData(std::string Columb)
{
//Set up command file path and command line command
std::string APPDATA = getenv("APPDATA");
std::string path = APPDATA + "\\localipdata.txt";
std::string cmd = "ipconfig > " + path;
//execute ipconfig command and save file to path
system(cmd.c_str());
//current line
std::string line;
//Line array : Here is all lines saved
std::string lineArray[500];
int arrayCount = 0;
std::ifstream file(path);
if (file.is_open())
{
//Get all lines
while (std::getline(file, line))
{
//Save each line into a element in an array
lineArray[arrayCount] = line;
arrayCount++;
}
for (int arrayindex = 0; arrayindex <= arrayCount; arrayindex++)
{
std::string s = Columb;
std::string s2 = ":";
//Search all lines and get pos
std::size_t i = lineArray[arrayindex].find(s);
std::size_t i2 = lineArray[arrayindex].find(s2);
//Found a match for Columb
if (lineArray[arrayindex].find(s) != std::string::npos)
{
//Validate
if (i != std::string::npos)
{
//Earse Columb name
lineArray[arrayindex].erase(i, s.length());
//Erase all blanks
lineArray[arrayindex].erase(remove_if(lineArray[arrayindex].begin(), lineArray[arrayindex].end(), isspace), lineArray[arrayindex].end());
//Found match for ':'
if (lineArray[arrayindex].find(s2) != std::string::npos)
{
//Validate
if (i2 != std::string::npos)
{
//Delete all characters prior to ':'
lineArray[arrayindex].erase(0, lineArray[arrayindex].find(":"));
lineArray[arrayindex].erase(std::remove(lineArray[arrayindex].begin(), lineArray[arrayindex].end(), ':'), lineArray[arrayindex].end());
}
}
//Return our data
return lineArray[arrayindex];
}
}
//Only go through all lines once
if (arrayindex == arrayCount)
break;
}
//Close file
file.close();
}
//Something went wrong
return "Invalid";
}
然后像这样调用它:
cout << parser.GetParsedIPConfigData("IPv4 Address") << "\n\n";