zoukankan      html  css  js  c++  java
  • LINUX

    Linux编程获取本机IP地址的几种方法

    参考:

    https://blog.csdn.net/zhongmushu/article/details/89944990

    https://www.cnblogs.com/lzpong/p/6956439.html

    在进行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

  • 相关阅读:
    Linux0.11内核--fork进程分析
    Linux0.11内核--内存管理之1.初始化
    Linux0.11内核--进程调度分析之2.调度
    Linux0.11内核--进程调度分析之1.初始化
    github
    推荐大家一个靠谱的论文检测平台。重复的部分有详细出处以及具体修改意见,能直接在文章上做修改,全部改完一键下载就搞定了。他们现在正在做毕业季活动, 赠送很多免费字数,可以说是十分划算了!地址是:https://www.paperpass.com/
    妈妈再也不用担心我找idea激活码了
    eclipse集成tomcat
    DNS--localhost
    RFC 2819)第5节"Definitions"除外的全部内容
  • 原文地址:https://www.cnblogs.com/wangqiwen-jer/p/12264127.html
Copyright © 2011-2022 走看看