Linux下编程获取本地IP地址的常见方法

获取本机IP地址,是一个相当灵活的操作,原因是网络地址的设置非常灵活而且都是允许用户进行个性化设置的。比如一台计算机上可以有多块物理网卡或者虚拟网卡,一个网卡上可以绑定多个IP地址,用户可以为网卡设置别名,可以重命名网卡。用户计算机所在网络拓扑结构未知,主机名设置是一个可选项,并且同样可以为一个计算机绑定多个主机名等,这些信息都会有影响。脱离了网络连接,单独的网络地址没有任何意义。编程中遇到必须获取计算机IP的场景,应该考虑将这一选项放到配置文件中,由用户自己来设置。

参考网络和书本,编程获取本机IP地址大约有以下几种方法。

方法一:ioctl()获取本地IP地址 Linux 下 可以使用ioctl()函数以及结构体 struct ifreq和结构体struct ifconf来获取网络接口的各种信息。

具体过程是先通过ictol获取本地的所有接口信息,存放到ifconf结构中,再从其中取出每个ifreq表示的ip信息(一般每个网卡对应一个IP地址,如:”eth0…、eth1…”)。

先了解结构体 struct ifreq和结构体struct ifconf:

//ifconf通常是用来保存所有接口信息的 //if.h struct ifconf { int ifc_len; /* size of buffer */ union { char *ifcu_buf; /*input from user->kernel*/ struct ifreq *ifcu_req; /* return from kernel->user*/ } ifc_ifcu; }; #define ifc_buf ifc_ifcu.ifcu_buf /*buffer address */ #define ifc_req ifc_ifcu.ifcu_req /*array of structures*/ //ifreq用来保存某个接口的信息 //if.h struct ifreq { char ifr_name[IFNAMSIZ]; union { struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; short ifru_flags; int ifru_metric; caddr_t ifru_data; } ifr_ifru; }; #define ifr_addr ifr_ifru.ifru_addr #define ifr_dstaddr ifr_ifru.ifru_dstaddr #define ifr_broadaddr ifr_ifru.ifru_broadaddr

如果本机的IP地址绑定在第一块网卡上,指定网卡名称,无需获取所有网卡的信息,即可获取,见如下函数:

string getLocalIP(){ int inet_sock; struct ifreq ifr; char ip[32]={NULL}; inet_sock = socket(AF_INET, SOCK_DGRAM, 0); strcpy(ifr.ifr_name, "eth0"); ioctl(inet_sock, SIOCGIFADDR, &ifr); strcpy(ip, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr)); return string(ip); }

如果想获取所有网络接口信息,参见如下代码:

#include <netdb.h> #include <arpa/inet.h> #include <sys/socket.h> #include <unistd.h> #include <sys/ioctl.h> #include <net/if.h> #include <stdio.h> #include <stdlib.h> int main(int argc,char* argv[]) { int sockfd; struct ifconf ifconf; struct ifreq *ifreq; char buf[512];//缓冲区 //初始化ifconf ifconf.ifc_len =512; ifconf.ifc_buf = buf; if ((sockfd =socket(AF_INET,SOCK_DGRAM,0))<0) { perror("socket" ); exit(1); } ioctl(sockfd, SIOCGIFCONF, &ifconf); //获取所有接口信息 //接下来一个一个的获取IP地址 ifreq = (struct ifreq*)ifconf.ifc_buf; printf("ifconf.ifc_len:%d\n",ifconf.ifc_len); printf("sizeof (struct ifreq):%d\n",sizeof (struct ifreq)); for (int i=(ifconf.ifc_len/sizeof (struct ifreq)); i>0; i--) { if(ifreq->ifr_flags == AF_INET){ //for ipv4 printf("name =[%s]\n" , ifreq->ifr_name); printf("local addr = [%s]\n" ,inet_ntoa(((struct sockaddr_in*)&(ifreq->ifr_addr))->sin_addr)); ifreq++; } } getchar();//system("pause");//not used in linux return 0; }

运行输出:

这里写图片描述

方法二:getsockname()获取本地IP地址 如果建立TCP连接的情况下,可以通过getsockname和getpeername函数来获取本地和对端的IP和端口号。前提是已经与对方建立了连接。 参考代码如下:

#include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <netdb.h> int main(int argc, char* argv[]) { int fd=socket(AF_INET,SOCK_STREAM,0);//创建本地sock描述符 struct sockaddr_in servaddr,localaddr,peeraddr; socklen_t len; //初始化服务端地址并连接 bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_port=htons(PORT);//PORT自己指定 char* servIP=”177.56.23.4”;//服务端IP inet_pton(AF_INET,servIP,&servaddr.sin_addr); if(connect(fd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0) { cerr<<"connect error"<<endl; return -1; } char buf[30]=""; bzero(&localaddr,sizeof(localaddr)); getsockname(fd,(struct sockaddr*)&localaddr,&len); //获取本地信息 cout<<"local ip is "<<inet_ntop(AF_INET,&localaddr.sin_addr,buf,sizeof(buf))<<"local port is"<<ntohs(localaddr.sin_port)<<endl; bzero(&peeraddr,sizeof(peeraddr)); getpeername(fd,(struct sockaddr*)&peeraddr,&len); //获取对端信息 cout<<"peer ip is "<< inet_ntop(AF_INET,&peeraddr.sin_addr,buf,sizeof(buf))<<"peer port is "<<ntohs(peeraddr.sin_port)<<endl; return 1; } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwzfwz.html