Linux编程获取本机IP地址的几种方法
参考:
在进行Linux网络编程时,经常会需要获取本机IP地址,除了常规的读取配置文件外,本文罗列几种个人所知的编程常用方法,仅供参考,如有错误请指出。
方法一:使用ioctl()获取本地IP地址
Linux下可以使用ioctl()函数以及结构体 struct ifreq和结构体struct ifconf来获取网络接口的各种信息。具体过程是先通过ictol获取本地所有接口的信息保存到ifconf结构中,再从其中取出每个ifreq表示的接口信息。
如果本机的IP地址绑定在第一块网卡上,则只需指定网卡名称,无需获取所有网卡的信息即可获取,见如下函数:
int get_localip(const char * eth_name, char *local_ip_addr) { int ret = -1; register int fd; struct ifreq ifr; if (local_ip_addr == NULL || eth_name == NULL) { return ret; } if ((fd=socket(AF_INET, SOCK_DGRAM, 0)) > 0) { strcpy(ifr.ifr_name, eth_name); if (!(ioctl(fd, SIOCGIFADDR, &ifr))) { ret = 0; strcpy(local_ip_addr, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr)); } } if (fd > 0) { close(fd); } return ret; }
如果想通过获取所有网络接口信息,示例代码如下:
#include <stdio.h> #include <net/if.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/ioctl.h> #include <netinet/in.h> int get_localip(const char * eth_name, char *local_ip_addr) { int ret = -1; register int fd, intrface; struct ifreq ifr[32]; struct ifconf ifc; if (local_ip_addr == NULL || eth_name == NULL) { return ret; } if ((fd=socket(AF_INET, SOCK_DGRAM, 0)) > 0) { ifc.ifc_len = sizeof ifr; ifc.ifc_buf = (caddr_t)ifr; if (!ioctl(fd, SIOCGIFCONF, (char*)&ifc)) //获取所有接口信息 { intrface = ifc.ifc_len / sizeof(struct ifreq); while (intrface-- > 0) { //Get IP Address if (!(ioctl(fd, SIOCGIFADDR, (char*)&ifr[intrface]))) { if(strcmp(eth_name, ifr[intrface].ifr_name) == 0) { ret = 0; sprintf(local_ip_addr, "%s", inet_ntoa(((struct sockaddr_in*)(&ifr[intrface].ifr_addr))->sin_addr)); break; } } } } } if (fd > 0) { close(fd); } return ret; } int main(int argc, const char **argv) { int ret; char local_ip[20] = {0}; ret = get_localip("eth0", local_ip); if (ret == 0) { printf("local ip:%s ", local_ip); } else { printf("get local ip failure "); } return 0; }
方法二:getsockname()获取本地IP地址
getsockname()用于获取一个已捆绑或已连接套接字的本地地址。若一个套接字与INADDR_ANY捆绑,也就是说该套接字可以用任意主机的地址,此时除非调用connect()或accept()来连接,否则getsockname()将不会返回主机IP地址的任何信息。
示例代码:
#include <stdio.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h> #define PORT 80 #define SERVER_IP "14.215.177.38" int main(int argc, const char **argv) { int ret = -1; socklen_t len; char buf[30] = {0}; struct sockaddr_in server_addr, local_addr; int fd = socket(AF_INET, SOCK_STREAM, 0); //int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd <= 0) { printf("fail to creat socket "); return -1; } memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT); server_addr.sin_addr.s_addr = inet_addr(SERVER_IP); if(connect(fd, (struct sockaddr*)&server_addr, sizeof(server_addr))<0) { printf("connect error!!! "); goto end; } len = sizeof(local_addr); memset(&local_addr, 0, sizeof(local_addr)); ret = getsockname(fd, (struct sockaddr*)&local_addr, &len); if (ret == 0) { printf("local ip is %s, local port is %d ", inet_ntop(AF_INET, &local_addr.sin_addr, buf, sizeof(buf)), ntohs(local_addr.sin_port)); } else { printf("getsockname failed, error=%d ", errno); } end: if (fd) { close(fd); } return ret; }
方法三:getaddrinfo()获取本地IP地址
getaddrinfo()可以完成网络主机中主机名和服务名到地址的映射,但是一般不能用来获取本地IP地址,当它用来获取本地IP地址时,返回的一般是127.0.0.1本地回环地址,且该函数仅仅支持IPv4。
示例代码:
#include <netdb.h> #include <stdio.h> #include <unistd.h> #include <arpa/inet.h> // 获取本地IP时,一般都是127.0.0.1 int main(int argc, const char **argv) { int ret; char host_name[128] = {0}; struct addrinfo *res, *cur; struct sockaddr_in *addr; if (gethostname(host_name, sizeof(host_name)) < 0) { printf("gethostname error "); return -1; } ret = getaddrinfo(host_name, NULL, NULL, &res); if (ret != 0) { printf("Error: error in getaddrinfo on hostname: %s ", gai_strerror(ret)); return -1; } for(cur = res; cur != NULL; cur = cur->ai_next) { if(cur->ai_family == AF_INET) { addr = (struct sockaddr_in*)cur->ai_addr; printf("local ip:%s ", inet_ntoa(addr->sin_addr)); } //char host[1024] = {0}; //ret = getnameinfo(cur->ai_addr, cur->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST); //if(ret != 0) //{ // printf("getnameinfo: %s ", gai_strerror(ret)); //} //else //{ // printf("ip: %s ", host); //} } freeaddrinfo(res); return 0; }
方法四:gethostbyname ()获取本地IP地址
gethostbyname()和getaddrinfo()的功能类似,一般用于通过主机名或者服务名,比如域名来获取主机的IP地址。但是要想获取本地IP地址的时候,一般获取的是回环地址127.0.0.1。
示例代码:
#include <netdb.h> #include <stdio.h> #include <unistd.h> #include <arpa/inet.h> // 获取本地IP时,一般都是127.0.0.1 int main(int argc, const char **argv) { int i = 0; char host_name[128] = {0}; struct hostent *hptr; if (gethostname(host_name, sizeof(host_name)) < 0) { printf("gethostname error "); return -1; } if ((hptr=gethostbyname(host_name)) == NULL) { printf("gethostbyname error "); return -1; } while(hptr->h_addr_list[i] != NULL) { printf("hostname: %s ", hptr->h_name); printf(" ip: %s ", inet_ntoa(*(struct in_addr*)hptr->h_addr_list[i])); i++; } return 0; }
方法五:通过getifaddrs()获取本地IP地址
/*代码来自StackOverflow:
http://stackoverflow.com/questions/212528/linux-c-get-the-ip-address-of-local-computer */
示例代码:
#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 ", 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 ", ifa->ifa_name, addressBuffer); } } if (ifAddrStruct!=NULL) { freeifaddrs(ifAddrStruct); } return 0; }
方法六:通过popen()调用ifconfig获取本地IP地址
用popen()建立一个管道,管道的一端执行命令ifconfig,管道的另一端读取收到的数据并进行相应的解析。这种方法需要执行shell命令,配合正则表达式,效率较低,一般不采用。而这种方式其实更倾向于配置,原因就是使用简单。
示例代码:
#include <stdio.h> #include <stdlib.h> #define ETH_NAME "ens33" int main(int argc, const char *argv[]) { FILE *fp; char buf[256] = {0}; char command[256] = {0}; //char *fmt = "ifconfig %s|sed -n '2p'|sed -n 's#^.*dr:##gp'|sed -n 's#B.*$##gp'"; char *fmt = "ifconfig %s|grep 'inet addr'|awk '{ print $2}' | awk -F: '{print $2}'"; snprintf(command, sizeof(command), fmt, ETH_NAME); if((fp = popen(command, "r")) == NULL) { perror("Fail to popen "); return -1; } while(fgets(buf, sizeof(buf), fp) != NULL) { printf("%s", buf); } pclose(fp); return 0; }
方法七:获取所有ip(ipv4+ipv6)
//#include <sys/types.h> #include <ifaddrs.h> #include <sys/ioctl.h> #include <net/if.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include <netdb.h> //#include <sys/socket.h> //#include <netinet/in.h> #include <arpa/inet.h> void pHx(unsigned char* p,int len){ printf("Hex: "); for(int i=0;i<len;i++){ printf("%02X:",p[i]); } printf(" "); } char* getMac(char* mac,char* dv){ struct ifreq ifreq; int sock; if(!mac || !dv) return mac; if((sock=socket(AF_INET,SOCK_STREAM,0)) <0) { perror( "socket "); return mac; } strcpy(ifreq.ifr_name,dv); if(ioctl(sock,SIOCGIFHWADDR,&ifreq) <0) { perror( "ioctl "); return mac; } pHx((unsigned char*)ifreq.ifr_hwaddr.sa_data,sizeof(ifreq.ifr_hwaddr.sa_data)); sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X", //以太网MAC地址的长度是48位 (unsigned char)ifreq.ifr_hwaddr.sa_data[0], (unsigned char)ifreq.ifr_hwaddr.sa_data[1], (unsigned char)ifreq.ifr_hwaddr.sa_data[2], (unsigned char)ifreq.ifr_hwaddr.sa_data[3], (unsigned char)ifreq.ifr_hwaddr.sa_data[4], (unsigned char)ifreq.ifr_hwaddr.sa_data[5]); return mac; } int main (int argc, const char * argv[]) { char hname[128]; struct hostent *hent; int i; gethostname(hname, sizeof(hname)); //hent = gethostent(); hent = gethostbyname(hname); printf("hostname: %s ", hent->h_name); //---------------------------------------------------------- printf(" "); char mac[30]; struct ifaddrs * ifap0=NULL,*ifap=NULL; void * tmpAddrPtr=NULL; getifaddrs(&ifap0); ifap=ifap0; while (ifap!=NULL) { if (ifap->ifa_addr->sa_family==AF_INET) { // check it is IP4 // is a valid IP4 Address tmpAddrPtr=&((struct sockaddr_in *)ifap->ifa_addr)->sin_addr; char addressBuffer[INET_ADDRSTRLEN]; inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); if(strcmp(addressBuffer,"127.0.0.1")!=0){ printf("%s IPv4: %s ", ifap->ifa_name, addressBuffer); printf("MAC: %s ",getMac(mac,ifap->ifa_name)); } } else if (ifap->ifa_addr->sa_family==AF_INET6) { // check it is IP6 // is a valid IP6 Address tmpAddrPtr=&((struct sockaddr_in *)ifap->ifa_addr)->sin_addr; char addressBuffer[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN); if(strcmp(addressBuffer,"::")!=0){ printf("%s IPv6: %s ", ifap->ifa_name, addressBuffer); printf("MAC: %s ",getMac(mac,ifap->ifa_name)); } } ifap=ifap->ifa_next; } if (ifap0) { freeifaddrs(ifap0); ifap0 = NULL; } return 0; }
参考文献
[1]https://blog.csdn.net/bailyzheng/article/details/7489656
[2]https://blog.csdn.net/k346k346/article/details/48231933
原文链接:https://blog.csdn.net/zhongmushu/article/details/89944990