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

在进行Linux网络编程时,常常用到本机IP地址。本文罗列一下常见方法,以备不时之需。
linux获取本机IP地址,是一个至关灵活的操做,缘由是网络地址的设置很是灵活并且都是容许用户进行个性化设置的。好比一台计算机上能够有多块物理网卡或者虚拟网卡,一个网卡上能够绑定多个IP地址,用户能够为网卡设置别名,能够重命名网卡。用户计算机所在网络拓扑结构未知,主机名设置是一个可选项,而且一样能够为一个计算机绑定多个主机名等,这些信息都会有影响。脱离了网络链接,单独的网络地址没有任何意义。编程中遇到必须获取计算机IP的场景,应该考虑将这一选项放到配置文件中,由用户本身来设置。
方法一:ioctl()获取本地IP地址
Linux 下 可使用ioctl()函数以及结构体 struct ifreq和结构体struct ifconf来获取网络接口的各类信息。网络具体过程是先经过ictol获取本地的全部接口信息,存放到ifconf结构中,再从其中取出每一个ifreq表示的ip信息(通常每一个网卡对应一个IP地址,如:”eth0…、eth1…”)。socket

先了解结构体 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;
}
}

下面两种方法,都是经过主机名称来获取主机的IP地址,在获取本地IP地址时,通常都是回环地址,但能够有效的根据主机名称获取网络中的主机的IP地址,如经过域名获取域名对应的IP地址。

要想精确的获取某块网卡绑定的IP地址,请根据ioctl()和接口名称(如eth0)来获取,具体实现见上文。

方法三:getaddrinfo()获取本地IP地址
注意,getaddrinfo()能够完成网络主机中主机名和服务名到地址的映射,可是通常不能用来获取本地IP地址,当它用来获取本地IP地址时,返回的通常是127.0.0.1本地回环地址。
所需头文件:

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

用例以下:

#include <netdb.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>

#include <stdio.h>
#include <stdlib.h>

int main(int argc,char* argv[])
{
    char host_name[128]={NULL};
    gethostname(host_name, sizeof(host_name));//获取本地主机名称
    printf("host_name:%s\n",host_name);

    struct addrinfo *ailist=NULL,*aip=NULL;
    struct sockaddr_in *saddr;
    char *addr;
    int ret=getaddrinfo(host_name,NULL,NULL,&ailist);
    for(aip=ailist; aip!=NULL; aip=aip->ai_next)
    {
        if(aip->ai_family==AF_INET)
        {
            saddr=(struct sockaddr_in*)aip->ai_addr;
            addr=inet_ntoa(saddr->sin_addr);
        }
        printf("addr:%s\n",addr);
    }

    printf("\n-----------------baidu host info-------------------\n");
    getaddrinfo("www.baidu.com","http",NULL,&ailist);
    for(aip=ailist; aip!=NULL; aip=aip->ai_next)
    {
        if(aip->ai_family==AF_INET)
        {
            saddr=(struct sockaddr_in*)aip->ai_addr;
            addr=inet_ntoa(saddr->sin_addr);
        }
        printf("baidu addr:%s\n",addr);
    }

    getchar(); 
    return 0;
}

使用gcc编译此程序会出现error: dereferencing pointer to incomplete type的错误,使用g++编译经过,程序输出:
在这里插入图片描述
方法四:gethostname()获取本地IP地址
gethostname()和getaddrinfo()的功能相似,通常用于经过主机名或者服务名,好比域名来获取主机的IP地址。可是要想获取本地IP地址的时候,通常获取的是回环地址127.0.0.1。

string getLocalIP(char* local_ip) {
    // 获取本地IP时,通常都是127.0.0.1
    char host_name[128]="";
    struct hostent *host_ent;
    gethostname(host_name, sizeof(host_name));
    host_ent = gethostbyname(host_name);
    const char* first_ip = inet_ntoa(*(struct in_addr*)(host_ent->h_addr_list[0]));
    memcpy(local_ip, first_ip, 16);
    return string(host_name);
}

注意,主机的地址是一个列表的形式,缘由是当一个主机有多个网络接口时,及多块网卡或者一个网卡绑定多个IP地址时,天然就有多个IP地址。以上代码获取的是根据主机名称获得的第一个IP地址。

参考文献
[1]http://blog.sina.com.cn/s/blog_9df3961501010hzj.html
[2]http://blog.csdn.net/darennet/article/details/9338819

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值