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

通过google,编程获取IP地址大约有以下三种思路:
1. 通过gethostname()和gethostbyname()

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

int main() {
    char hname[128];
    struct hostent *hent;
    int i;

gethostname(hname, sizeof(hname));

//hent = gethostent();
    hent = gethostbyname(hname);

printf("hostname: %s/naddress list: ", hent->h_name);
    for(i = 0; hent->h_addr_list[i]; i++) {
        printf("%s/t", inet_ntoa(*(struct in_addr*)(hent->h_addr_list[i])));
    }
    return 0;
}

运行:
[whb@jcwkyl c]$ ./local_ip
hostname: jcwkyl.jlu.edu.cn
address list: 10.60.56.90

2. 通过枚举网卡,API接口可查看man 7 netdevice

/*代码来自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;
    void * tmpAddrPtr=NULL;

getifaddrs(&ifAddrStruct);

while (ifAddrStruct!=NULL) {
        if (ifAddrStruct->ifa_addr->sa_family==AF_INET) { // check it is IP4
            // is a valid IP4 Address
           tmpAddrPtr=&((struct sockaddr_in*)ifAddrStruct->ifa_addr)->sin_addr;
            char addressBuffer[INET_ADDRSTRLEN];
           inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
           printf("%s IP Address %s/n", ifAddrStruct->ifa_name, addressBuffer);
        } else if (ifAddrStruct->ifa_addr->sa_family==AF_INET6) { // check it is IP6
            // is a valid IP6 Address
           tmpAddrPtr=&((struct sockaddr_in*)ifAddrStruct->ifa_addr)->sin_addr;
            char addressBuffer[INET6_ADDRSTRLEN];
           inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
           printf("%s IP Address %s/n", ifAddrStruct->ifa_name, addressBuffer);
        }
        ifAddrStruct=ifAddrStruct->ifa_next;
    }
    return 0;
}

运行 :
[whb@jcwkyl c]$ ./local_ip2
lo IP Address 127.0.0.1
eth0 IP Address 10.60.56.90
eth0:1 IP Address 192.168.1.3
lo IP Address ::
eth0 IP Address ::2001:da8:b000:6213:20f:1fff
eth0 IP Address 0:0:fe80::20f:1fff

3. 打开一个对外界服务器的网络连接,通过getsockname()反查自己的IP

补充:

在linux下 获取,修改本机IP地址的两个函数

//获取本机IP地址函数

view plaincopy to clipboardprint?
  1. QString GetLocalIp()
  2. {
  3. int sock_get_ip;
  4. char ipaddr[50];
  5. struct   sockaddr_in *sin;
  6. struct   ifreq ifr_ip;
  7. if ((sock_get_ip=socket(AF_INET, SOCK_STREAM, 0)) == -1)
  8. {
  9. printf("socket create failse...GetLocalIp!/n");
  10. return "";
  11. }
  12. memset(&ifr_ip, 0, sizeof(ifr_ip));
  13. strncpy(ifr_ip.ifr_name, "eth0", sizeof(ifr_ip.ifr_name) - 1);
  14. if( ioctl( sock_get_ip, SIOCGIFADDR, &ifr_ip) < 0 )
  15. {
  16. return "";
  17. }
  18. sin = (struct sockaddr_in *)&ifr_ip.ifr_addr;
  19. strcpy(ipaddr,inet_ntoa(sin->sin_addr));
  20. printf("local ip:%s /n",ipaddr);
  21. close( sock_get_ip );
  22. return QString( ipaddr );
  23. }

//修改本机IP地址的函数

  1. int SetLocalIp( const char *ipaddr )
  2. {
  3. int sock_set_ip;
  4. struct sockaddr_in sin_set_ip;
  5. struct ifreq ifr_set_ip;
  6. bzero( &ifr_set_ip,sizeof(ifr_set_ip));
  7. if( ipaddr == NULL )
  8. return -1;
  9. if(sock_set_ip = socket( AF_INET, SOCK_STREAM, 0 ) == -1);
  10. {
  11. perror("socket create failse...SetLocalIp!/n");
  12. return -1;
  13. }
  14. memset( &sin_set_ip, 0, sizeof(sin_set_ip));
  15. strncpy(ifr_set_ip.ifr_name, "eth0", sizeof(ifr_set_ip.ifr_name)-1);
  16. sin_set_ip.sin_family = AF_INET;
  17. sin_set_ip.sin_addr.s_addr = inet_addr(ipaddr);
  18. memcpy( &ifr_set_ip.ifr_addr, &sin_set_ip, sizeof(sin_set_ip));
  19. if( ioctl( sock_set_ip, SIOCSIFADDR, &ifr_set_ip) < 0 )
  20. {
  21. perror( "Not setup interface/n");
  22. return -1;
  23. }
  24. //设置激活标志
  25. ifr_set_ip.ifr_flags |= IFF_UP |IFF_RUNNING;
  26. //get the status of the device
  27. if( ioctl( sock_set_ip, SIOCSIFFLAGS, &ifr_set_ip ) < 0 )
  28. {
  29. perror("SIOCSIFFLAGS");
  30. return -1;
  31. }
  32. close( sock_set_ip );
  33. return 0;
  34. }

在linux下 获取本机MAC地址的函数

获取本机MAC地址函数

  1. QString GetLocalMac()
  2. {
  3. int sock_mac;
  4. struct ifreq ifr_mac;
  5. char mac_addr[30];
  6. sock_mac = socket( AF_INET, SOCK_STREAM, 0 );
  7. if( sock_mac == -1)
  8. {
  9. perror("create socket falise...mac/n");
  10. return "";
  11. }
  12. memset(&ifr_mac,0,sizeof(ifr_mac));
  13. strncpy(ifr_mac.ifr_name, "eth0", sizeof(ifr_mac.ifr_name)-1);
  14. if( (ioctl( sock_mac, SIOCGIFHWADDR, &ifr_mac)) < 0)
  15. {
  16. printf("mac ioctl error/n");
  17. return "";
  18. }
  19. sprintf(mac_addr,"%02x%02x%02x%02x%02x%02x",
  20. (unsigned char)ifr_mac.ifr_hwaddr.sa_data[0],
  21. (unsigned char)ifr_mac.ifr_hwaddr.sa_data[1],
  22. (unsigned char)ifr_mac.ifr_hwaddr.sa_data[2],
  23. (unsigned char)ifr_mac.ifr_hwaddr.sa_data[3],
  24. (unsigned char)ifr_mac.ifr_hwaddr.sa_data[4],
  25. (unsigned char)ifr_mac.ifr_hwaddr.sa_data[5]);
  26. printf("local mac:%s /n",mac_addr);
  27. close( sock_mac );
  28. return QString( mac_addr );
  29. }

在linux下 获取,修改子网掩码NETMASK的两个函数

//获取子网掩码的函数

  1. QString GetLocalNetMask()
  2. {
  3. int sock_netmask;
  4. char netmask_addr[50];
  5. struct ifreq ifr_mask;
  6. struct sockaddr_in *net_mask;
  7. sock_netmask = socket( AF_INET, SOCK_STREAM, 0 );
  8. if( sock_netmask == -1)
  9. {
  10. perror("create socket failture...GetLocalNetMask/n");
  11. return "";
  12. }
  13. memset(&ifr_mask, 0, sizeof(ifr_mask));
  14. strncpy(ifr_mask.ifr_name, ifname, sizeof(ifr_mask.ifr_name )-1);
  15. if( (ioctl( sock_netmask, SIOCGIFNETMASK, &ifr_mask ) ) < 0 )
  16. {
  17. printf("mac ioctl error/n");
  18. return "";
  19. }
  20. net_mask = ( struct sockaddr_in * )&( ifr_mask.ifr_netmask );
  21. strcpy( netmask_addr, inet_ntoa( net_mask -> sin_addr ) );
  22. printf("local netmask:%s/n",netmask_addr);
  23. close( sock_netmask );
  24. return QString( netmask_addr );
  25. }

//修改子NETMASK的函数

  1. QString SetLocalNetMask(const char *szNetMask)
  2. {
  3. int sock_netmask;
  4. char netmask_addr[32];
  5. struct ifreq ifr_mask;
  6. struct sockaddr_in *sin_net_mask;
  7. sock_netmask = socket( AF_INET, SOCK_STREAM, 0 );
  8. if( sock_netmask == -1)
  9. {
  10. perror("Not create network socket connect/n");
  11. return "";
  12. }
  13. memset(&ifr_mask, 0, sizeof(ifr_mask));
  14. strncpy(ifr_mask.ifr_name, "eth0", sizeof(ifr_mask.ifr_name )-1);
  15. sin_net_mask = (struct sockaddr_in *)&ifr_mask.ifr_addr;
  16. sin_net_mask -> sin_family = AF_INET;
  17. inet_pton(AF_INET, szNetMask, &sin_net_mask ->sin_addr);
  18. if(ioctl(sock_netmask, SIOCSIFNETMASK, &ifr_mask ) < 0)
  19. {
  20. printf("sock_netmask ioctl error/n");
  21. return "";
  22. }
  23. }

//获去GateWay

  1. QString GetGateWay()
  2. {
  3. FILE *fp;
  4. char buf[512];
  5. char cmd[128];
  6. char gateway[30];
  7. char *tmp;
  8. strcpy(cmd, "ip route");
  9. fp = popen(cmd, "r");
  10. if(NULL == fp)
  11. {
  12. perror("popen error");
  13. return "";
  14. }
  15. while(fgets(buf, sizeof(buf), fp) != NULL)
  16. {
  17. tmp =buf;
  18. while(*tmp && isspace(*tmp))
  19. ++ tmp;
  20. if(strncmp(tmp, "default", strlen("default")) == 0)
  21. break;
  22. }
  23. sscanf(buf, "%*s%*s%s", gateway);
  24. printf("default gateway:%s/n", gateway);
  25. pclose(fp);
  26. return QString(gateway);
  27. }

//设置网关

  1. int SetGateWay(const char *szGateWay)
  2. {
  3. int ret = 0;
  4. char cmd[128];
  5. QString DefGW = GetGateWay();
  6. const char *strGW = DefGW.latin1();
  7. strcpy(cmd, "route del default gw ");
  8. strcat(cmd, strGW);
  9. ret = system(cmd);
  10. if(ret < 0)
  11. {
  12. perror("route error");
  13. return -1;
  14. }
  15. strcpy(cmd, "route add default gw ");
  16. strcat(cmd, szGateWay);
  17. ret = system(cmd);
  18. if(ret < 0)
  19. {
  20. perror("route error");
  21. return -1;
  22. }
  23. return ret;
  24. }

补充2:

有时候,写程序的时候需要获取计算机的网络信息,比如IP地址、电脑名称、DNS等信息。IP地址和电脑名称是比较容易获取到的,而要想获取地址掩码、DNS、网关等信息就有些麻烦了。

在Windows下我们一般都是通过从注册表读取这些信息。在Linux怎么做呢?其实,Linux下更加容易一些。因为我们可以拿现成的程序看它的源代码。通过阅读其源代码找到解决该问题的方法。那么,看哪个程序的源代码呢?如果你使用过Linux,并且比较熟悉的话就肯定知道一个命令ifconfig。这个命令和Windows下的ipconfig差不多,都可以输出网卡的信息,其中就包含DNS、掩码等信息。所以,我们可以通过看它的源代码来找到解决该问题的方法。

获取系统中的网卡数量

并没有那个系统调用提供网卡数量的获取。但是,我们可以通过强大的proc文件系统获取网卡数量的信息。实际上,ifconfig也是这样做的,请看示例代码如下: 
0001 #include <stdio.h>
0002 #include <string.h>
0003 #include <errno.h>
0004 
0005 int GetNetCardCount()
0006 {
0007     int nCount = 0;
0008     FILE* f = fopen("/proc/net/dev", "r");
0009     if (!f)
0010     {
0011         fprintf(stderr, "Open /proc/net/dev failed!errno:%d\n", errno);
0012         return nCount;
0013     }
0014 
0015     char szLine[512];
0016 
0017     fgets(szLine, sizeof(szLine), f);    /* eat line */
0018     fgets(szLine, sizeof(szLine), f);
0019 
0020     while(fgets(szLine, sizeof(szLine), f))
0021     {
0022         char szName[128] = {0};
0023         sscanf(szLine, "%s", szName);
0024         int nLen = strlen(szName);
0025         if (nLen <= 0)continue;
0026         if (szName[nLen - 1] == ':') szName[nLen - 1] = 0;
0027         if (strcmp(szName, "lo") == 0)continue;
0028         nCount++;
0029     }
0030 
0031     fclose(f);
0032     f = NULL;
0033     return nCount;
0034 }
0035 
0036 int main(int argc, char* argv[])
0037 {
0038     printf("NetCardCount: %d\n", GetNetCardCount());
0039     return 0;
0040 }

获取IP、掩码、MAC及网关

获取IP、掩码、MAC和广播地址是比较容易的,只需要调用对应的IOCTL即可。只是大家对Linux下的IOCTL可能不太熟悉。却看示例代码:

0001 void DispNetInfo(const char* szDevName)
0002 {
0003     int s = socket(AF_INET, SOCK_DGRAM, 0);
0004     if (s < 0)
0005     {
0006         fprintf(stderr, "Create socket failed!errno=%d", errno);
0007         return;
0008     }
0009 
0010     struct ifreq ifr;
0011     unsigned char mac[6];
0012     unsigned long nIP, nNetmask, nBroadIP;
0013 
0014     printf("%s:\n", szDevName);
0015 
0016     strcpy(ifr.ifr_name, szDevName);
0017     if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0)
0018     {
0019         return;
0020     }
0021     memcpy(mac, ifr.ifr_hwaddr.sa_data, sizeof(mac));
0022     printf("\tMAC: %02x-%02x-%02x-%02x-%02x-%02x\n",
0023             mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
0024 
0025     strcpy(ifr.ifr_name, szDevName);
0026     if (ioctl(s, SIOCGIFADDR, &ifr) < 0)
0027     {
0028         nIP = 0;
0029     }
0030     else
0031     {
0032         nIP = *(unsigned long*)&ifr.ifr_broadaddr.sa_data[2];
0033     }
0034     printf("\tIP: %s\n", inet_ntoa(*(in_addr*)&nIP));
0035 
0036     strcpy(ifr.ifr_name, szDevName);
0037     if (ioctl(s, SIOCGIFBRDADDR, &ifr) < 0)
0038     {
0039         nBroadIP = 0;
0040     }
0041     else
0042     {
0043         nBroadIP = *(unsigned long*)&ifr.ifr_broadaddr.sa_data[2];
0044     }
0045     printf("\tBroadIP: %s\n", inet_ntoa(*(in_addr*)&nBroadIP));
0046 
0047     strcpy(ifr.ifr_name, szDevName);
0048     if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0)
0049     {
0050         nNetmask = 0;
0051     }
0052     else
0053     {
0054         nNetmask = *(unsigned long*)&ifr.ifr_netmask.sa_data[2];
0055     }
0056     printf("\tNetmask: %s\n", inet_ntoa(*(in_addr*)&nNetmask));
0057     close(s);
0058 }

那么如何获取网关地址呢?更加容易,但是,好像很少有人知道。反正我在网上没有找到有人知道。最后看了nslookup的源代码以后才知道正确的做法。代码如下:

res_init();

for (int i = 0; i < _res.nscount; i++)

{

struct sockaddr* server = (struct sockaddr*)&_res.nsaddr_list[i];

printf("Server:  %s\n", inet_ntoa(*(in_addr*)&(server->sa_data[2])));

}

代码很简单,就不做解释了。

怎么获取网关呢?这个稍微有点麻烦一些,不过和获取网卡数量相似,都是通过proc文件系统。这次分析的/proc/net/route文件。我就不再贴出示例代码了。

最后,我把运行示例程序获取到的信息附上,以供大家有个直观的认识:

eth0:

MAC: 08-00-27-98-bf-f3

IP: 192.168.1.106

BroadIP: 255.255.255.255

Netmask: 255.255.255.0

Gateway: 192.168.1.1

eth1:

MAC: 08-00-27-16-f4-bf

IP: 192.168.1.108

BroadIP: 192.168.1.255

Netmask: 255.255.255.0

Gateway: 0.0.0.0

eth2:

MAC: 08-00-27-37-9c-91

IP: 0.0.0.0

BroadIP: 0.0.0.0

Netmask: 0.0.0.0

Gateway: 0.0.0.0

eth3:

MAC: 08-00-27-5a-d2-39

IP: 0.0.0.0

BroadIP: 0.0.0.0

Netmask: 0.0.0.0

Gateway: 0.0.0.0

NetCardCount: 4

DNS 0:  218.2.135.1

DNS 1:  61.147.37.1

补充3:

Linux下的网络配置包含三个要素,分别是IP地址、子网掩码和网关。本文将介绍如何在C语言中进行网络的配置和配置信息的获取。

【配置】

方法一

使用system()或exec*()调用ifconfig和route命令进行配置。这种方法的优点是使用简单,缺点是效率比较低,且依赖于ifconfig与route命令。

示例:

见所附代码中的函数ip_config_system()和ip_config_exec()。

方法二

建立一个socket,用ioctl()进行配置。这种方法的优点是效率较高,缺点是程序实现起来比较麻烦。

示例:

见所附代码中的函数ip_config_ioctl()。

【获取】

方法一

用popen()建立一个管道,管道的一端执行命令ifconfig和route,管道的另一端读取收到的数据并进行相应的解析。这种方法的优点是使用简单,缺点是效率比较低,且依赖于ifconfig与route命令。

示例:

见所附代码中的函数ip_get_pipe()。

方法二

用fopen()打开/proc/net/route,可以获取网关(在/proc/net中尚未发现比较好的获取IP地址和掩码的方法,知道的请发邮件至cugfeng at gamil.com,谢谢)。这种方法的优点是使用简单,效率比执行命令高,缺点是依赖于proc文件系统。

示例:

见所附代码中的函数ip_get_proc()。

方法三

建立一个socket,用ioctl()进行获取(用ioctl()尚未发现比较好的获取网关的方法,知道的请发邮件至cugfeng at gamil.com,谢谢)。这种方法的优点是效率较高,缺点是程序实现起来比较麻烦。

示例:

见所附代码中的函数ip_get_ioctl()。

BTW,用ioctl()的方法还可以获取MAC地址,ioctl()命令为SIOCGIFHWADDR,具体用法与ioctl()获取IP地址的方法相同,这里就不多说了。

linux编程获取本机IP地址的三种方法相关推荐

  1. (转载)Linux编程获取本机IP地址的三种方法

    (转载)http://blog.csdn.net/jcwKyl/article/details/6324147 这 是一项不太清晰而且没有多大意义的工作.一个原因是网络地址的设置非常灵活而且都是允许用 ...

  2. Linux编程获取本机IP地址

    使用函数getifaddrs来枚举网卡IP,当中使用到的结构体例如以下所看到的: struct ifaddrs { struct ifaddrs *ifa_next; /* Next item in ...

  3. C#如何获取本机IP地址,两种方法

    using System; using System.Net;namespace test {class Program{static void Main(string[] args){//获取本机所 ...

  4. PHP获取用户访问IP地址的5种方法

    PHP获取用户访问IP地址的5种方法: //方法1: <?php                                                                 ...

  5. c# 获得本地ip地址的三种方法

    网上有很多种方法可以获取到本地的IP地址.一线常用的有这么些: 枚举本地网卡 using System.Net.NetworkInformation; using System.Net.Sockets ...

  6. C#获取本机IP地址的4种方式

    1.使用 Dns.GetHostEntry() 函数获取本地 IP 地址 Dns 类获取与 Internet 上的主机有关的信息.在 C# 中,Dns 类中有很多方法可以实现 DNS 相关功能.其中 ...

  7. Python获取IP地址的三种方法

    在python中获取IP地址的方法很简单,我们只和gethostbyname和gethostbyname_ex两个函数可以实现了,当然也可以利用公网api来实现. 使用拨号上网的话,一般都有一个本地i ...

  8. Ubuntu 18.04 查看本机IP地址的两种方法 ip和ifconfig

    Linux查看本机IP有两种方法,一种方法是使用废弃的ifconfig,第二种方法是使用内置的ip. 在Ubuntu 18.04中, net-tools 工具包没有被默认安装,这就意味着不能使用 if ...

  9. 虚拟机下CentOS 6.5配置IP地址的三种方法

    实验软件环境:虚拟机Vmware Workstation10.0 .CentOS 6.5 32位 1.自动获取IP地址 虚拟机使用桥接模式,相当于连接到物理机的网络里,物理机网络有DHCP服务器自动分 ...

最新文章

  1. SQL XML 字段操作
  2. python安装第三方库太慢_Python 安装第三方库 pip install 安装慢安装不上的解决办法...
  3. 虎扑签约神策数据,媒体 + 电商数据新玩法
  4. Oracle 共享锁和排它锁、 DML和DDL锁、 for update 锁表的问题
  5. P4457-[BJOI2018]治疗之雨【期望dp,高斯消元】
  6. 代码扫描工具测试覆盖率工具
  7. 用机械硬盘安装linux,HDD 机械硬盘 安装 linux(centos7)
  8. 揭秘世界首位机器人公民:按照赫本形象设计、曾扬言毁灭人类
  9. 杭州29岁IT男凌晨突发脑出血!老父亲面对医生急的差点跪下
  10. C# 在采集数据时的验证与登录处理
  11. 2018年7-8月学习有效反馈
  12. 计算机网络:网络常用命令的使用及DNS层次查询、SMTP协议分析
  13. 2020年高教社杯全国大学生数学建模竞赛题目D题 接触式轮廓仪的自动标注
  14. 机器学习Sklearn——红酒分类案例详解决策树模型参数
  15. switch日文键盘打中文_12月有哪些Switch游戏值得期待?
  16. 达内python培训班靠谱吗
  17. Git 同步代码两例常见报错
  18. 鸽子学Python 之 Pandas数据分析库
  19. 社区宽带繁忙是什么意思_康平附近企业宽带价位,附近光纤宽带上门安装多少钱...
  20. 一家之言—通信专业IT男的弊端

热门文章

  1. 动态规划:0-1背包问题(递归+备忘录)
  2. Excel按颜色求和,计数,均值
  3. SpringSecurity Oauth2 认证授权(二)springboot快速入门与底层介绍
  4. 如何营造性能至上的团队文化
  5. 程序员都逃不脱35岁失业的魔咒?
  6. 可以为linux提交代码,大学教授「故意」向 Linux 提交含 Bug 代码
  7. mysql写入一句话木马
  8. 计算机研究热点发展趋势,[精品]计算机科学前沿热点及发展趋势.doc
  9. 多个Serial.print拼成一条Serial.print省时间吗?
  10. 如何正确的进行亚马逊关键词研究