Linux获取本机IP、MAC地址⽤法⼤全
ifaddrs结构体定义如下:
1struct ifaddrs
2 {
3struct ifaddrs  *ifa_next;    /* Next item in list */
4char            *ifa_name;    /* Name of interface */
5    unsigned int    ifa_flags;  /* Flags from SIOCGIFFLAGS */
6struct sockaddr *ifa_addr;    /* Address of interface */
7struct sockaddr *ifa_netmask; /* Netmask of interface */
8    union
9    {
10struct sockaddr *ifu_broadaddr; /* Broadcast address of interface */
linux怎么读取windows文件11struct sockaddr *ifu_dstaddr; /* Point-to-point destination address */
12    } ifa_ifu;
13#define              ifa_broadaddr ifa_ifu.ifu_broadaddr
14#define              ifa_dstaddr  ifa_ifu.ifu_dstaddr
15void            *ifa_data;    /* Address-specific data */
16 };
ifa_next指向链表的下⼀个成员;ifa_name是接⼝名称,以0结尾的字符串,⽐如eth0,lo;ifa_flags是接⼝的标识位(⽐如当IFF_BROADCAST或IFF_POINTOPOINT设置到此标识位时,影响联合体变量ifu_broadaddr存储⼴播地址或ifu_dstaddr记录点对点地址);ifa_netmask存储该接⼝的⼦⽹掩码;结构体变量存储⼴播地址或点对点地址(见括弧介绍ifa_flags);ifa_data存储了该接⼝协议族的特殊信息,它通常是NULL(⼀般不关注他)。
函数getifaddrs(int getifaddrs (struct ifaddrs **__ifap))获取本地⽹络接⼝信息,将之存储于链表中,链表头结点指针存储于__ifap中带回,函数执⾏成功返回0,失败返回-1,且为errno赋值。
很显然,函数getifaddrs⽤于获取本机接⼝信息,⽐如最典型的获取本机IP地址。
这是⼀项不太清晰⽽且没有多⼤意义的⼯作。⼀个原因是⽹络地址的设置⾮常灵活⽽且都是允许⽤户进⾏个性化设置的,⽐如⼀台计算机上可以有多块物理⽹卡或者虚拟⽹卡,⼀个⽹卡上可以绑定多个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])));
}
return0;
}
运⾏:
[whb@jcwkyl c]$ ./local_ip
hostname: jcwkyl.jlu.edu
address list: 10.60.56.90
2. 通过枚举⽹卡,API接⼝可查看man 7 netdevice
/*代码来⾃StackOverflow: stackoverflow/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;
}
return0;
}
运⾏:
[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地址函数
1 QString GetLocalIp()
2 {
3
4int sock_get_ip;
5char ipaddr[50];
6
7struct  sockaddr_in *sin;
8struct  ifreq ifr_ip;
9
10if ((sock_get_ip=socket(AF_INET, SOCK_STREAM, 0)) == -1)
11    {
12          printf("socket GetLocalIp!/n");
13return"";
14    }
15
16    memset(&ifr_ip, 0, sizeof(ifr_ip));
17    strncpy(ifr_ip.ifr_name, "eth0", sizeof(ifr_ip.ifr_name) - 1);
18
19if( ioctl( sock_get_ip, SIOCGIFADDR, &ifr_ip) < 0 )
20    {
21return"";
22    }
23    sin = (struct sockaddr_in *)&ifr_ip.ifr_addr;
24    strcpy(ipaddr,inet_ntoa(sin->sin_addr));
25
26    printf("local ip:%s /n",ipaddr);
27    close( sock_get_ip );
28
29return QString( ipaddr );
30 }
//修改本机IP地址的函数
1int SetLocalIp( const char *ipaddr )
2 {
3
4int sock_set_ip;
5
6struct sockaddr_in sin_set_ip;
7struct ifreq ifr_set_ip;
8
9    bzero( &ifr_set_ip,sizeof(ifr_set_ip));
10
11if( ipaddr == NULL )
12return -1;
13
14if(sock_set_ip = socket( AF_INET, SOCK_STREAM, 0 ) == -1);
15    {
16        perror("socket SetLocalIp!/n");
17return -1;
18    }
19
20    memset( &sin_set_ip, 0, sizeof(sin_set_ip));
21    strncpy(ifr_set_ip.ifr_name, "eth0", sizeof(ifr_set_ip.ifr_name)-1);
22
23    sin_set_ip.sin_family = AF_INET;
24    sin_set_ip.sin_addr.s_addr = inet_addr(ipaddr);
25    memcpy( &ifr_set_ip.ifr_addr, &sin_set_ip, sizeof(sin_set_ip));
26
27if( ioctl( sock_set_ip, SIOCSIFADDR, &ifr_set_ip) < 0 )
28    {
29        perror( "Not setup interface/n");
30return -1;
31    }
32
33//设置激活标志
34    ifr_set_ip.ifr_flags |= IFF_UP |IFF_RUNNING;
35
36//get the status of the device
37if( ioctl( sock_set_ip, SIOCSIFFLAGS, &ifr_set_ip ) < 0 )
38    {
39          perror("SIOCSIFFLAGS");
40return -1;
41    }
42
43    close( sock_set_ip );
44return0;
45 }
在linux下获取本机MAC地址的函数
获取本机MAC地址函数
1 QString GetLocalMac()
2 {
3int sock_mac;
4
5struct ifreq ifr_mac;
6char mac_addr[30];
7
8    sock_mac = socket( AF_INET, SOCK_STREAM, 0 );
9if( sock_mac == -1)
10    {
11        perror("create ac/n");
12return"";
13    }
14
15    memset(&ifr_mac,0,sizeof(ifr_mac));
16    strncpy(ifr_mac.ifr_name, "eth0", sizeof(ifr_mac.ifr_name)-1);
17
18if( (ioctl( sock_mac, SIOCGIFHWADDR, &ifr_mac)) < 0)
19    {
20        printf("mac ioctl error/n");
21return"";
22    }
23
24    sprintf(mac_addr,"%02x%02x%02x%02x%02x%02x",
25            (unsigned char)ifr_mac.ifr_hwaddr.sa_data[0],
26            (unsigned char)ifr_mac.ifr_hwaddr.sa_data[1],
27            (unsigned char)ifr_mac.ifr_hwaddr.sa_data[2],
28            (unsigned char)ifr_mac.ifr_hwaddr.sa_data[3],
29            (unsigned char)ifr_mac.ifr_hwaddr.sa_data[4],
30            (unsigned char)ifr_mac.ifr_hwaddr.sa_data[5]);
31
32    printf("local mac:%s /n",mac_addr);
33
34    close( sock_mac );
35return QString( mac_addr );
36 }
在linux下获取,修改⼦⽹掩码NETMASK的两个函数
/
/获取⼦⽹掩码的函数
1 QString GetLocalNetMask()
2 {
3int sock_netmask;
4char netmask_addr[50];
5
6struct ifreq ifr_mask;
7struct sockaddr_in *net_mask;
8
9    sock_netmask = socket( AF_INET, SOCK_STREAM, 0 );
10if( sock_netmask == -1)
11    {
12        perror("create GetLocalNetMask/n");
13return"";
14    }
15
16    memset(&ifr_mask, 0, sizeof(ifr_mask));
17    strncpy(ifr_mask.ifr_name, ifname, sizeof(ifr_mask.ifr_name )-1);
18
19if( (ioctl( sock_netmask, SIOCGIFNETMASK, &ifr_mask ) ) < 0 )
20    {
21        printf("mac ioctl error/n");
22return"";
23    }
24
25    net_mask = ( struct sockaddr_in * )&( ifr_mask.ifr_netmask );
26    strcpy( netmask_addr, inet_ntoa( net_mask -> sin_addr ) );
27
28    printf("local netmask:%s/n",netmask_addr);
29
30    close( sock_netmask );
31return QString( netmask_addr );
32 }
/
/修改⼦NETMASK的函数
1 QString SetLocalNetMask(const char *szNetMask)
2 {
3int sock_netmask;
4char netmask_addr[32];
5
6struct ifreq ifr_mask;
7struct sockaddr_in *sin_net_mask;
8
9    sock_netmask = socket( AF_INET, SOCK_STREAM, 0 );
10if( sock_netmask == -1)
11    {
12        perror("Not create network socket connect/n");
13return"";
14    }
15
16    memset(&ifr_mask, 0, sizeof(ifr_mask));
17    strncpy(ifr_mask.ifr_name, "eth0", sizeof(ifr_mask.ifr_name )-1);
18    sin_net_mask = (struct sockaddr_in *)&ifr_mask.ifr_addr;
19    sin_net_mask -> sin_family = AF_INET;
20    inet_pton(AF_INET, szNetMask, &sin_net_mask ->sin_addr);
21
22if(ioctl(sock_netmask, SIOCSIFNETMASK, &ifr_mask ) < 0)
23    {
24        printf("sock_netmask ioctl error/n");
25return"";
26    }
27 }
//获去GateWay
1 QString GetGateWay()
2 {
3    FILE *fp;
4char buf[512];
5char cmd[128];
6char gateway[30];
7char *tmp;
8
9    strcpy(cmd, "ip route");
10    fp = popen(cmd, "r");
11if(NULL == fp)
12    {
13        perror("popen error");
14return"";
15    }
16while(fgets(buf, sizeof(buf), fp) != NULL)
17    {
18        tmp =buf;
19while(*tmp && isspace(*tmp))
20            ++ tmp;
21if(strncmp(tmp, "default", strlen("default")) == 0)
22break;
23    }
24    sscanf(buf, "%*s%*s%s", gateway);
25    printf("default gateway:%s/n", gateway);
26    pclose(fp);
27
28return QString(gateway);
29 }
//设置⽹关
1int SetGateWay(const char *szGateWay)
2 {
3int ret = 0;
4char cmd[128];
5    QString DefGW = GetGateWay();
6
7const char *strGW = DefGW.latin1();
8
9    strcpy(cmd, "route del default gw ");
10    strcat(cmd, strGW);
11    ret = system(cmd);
12if(ret < 0)
13    {
14        perror("route error");
15return -1;
16    }
17    strcpy(cmd, "route add default gw ");
18    strcat(cmd, szGateWay);
19
20    ret = system(cmd);
21if(ret < 0)
22    {
23        perror("route error");
24return -1;
25    }
26
27return ret;
28 }
Linux下如何获取⽹卡信息
有时候,写程序的时候需要获取计算机的⽹络信息,⽐如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
0005int GetNetCardCount()
0006 {
0007int nCount = 0;
0008    FILE* f = fopen("/proc/net/dev", "r");
0009if (!f)
0010    {
0011        fprintf(stderr, "Open /proc/net/dev failed!errno:%d\n", errno);
0012return nCount;
0013    }
0014
0015char szLine[512];
0016
0017    fgets(szLine, sizeof(szLine), f);    /* eat line */
0018    fgets(szLine, sizeof(szLine), f);
0019
0020while(fgets(szLine, sizeof(szLine), f))
0021    {
0022char szName[128] = {0};
0023        sscanf(szLine, "%s", szName);
0024int nLen = strlen(szName);
0025if (nLen <= 0)continue;
0026if (szName[nLen - 1] == ':') szName[nLen - 1] = 0;
0027if (strcmp(szName, "lo") == 0)continue;
0028        nCount++;
0029    }
0030
0031    fclose(f);
0032    f = NULL;
0033return nCount;
0034 }
0035
0036int main(int argc, char* argv[])
0037 {
0038    printf("NetCardCount: %d\n", GetNetCardCount());
0039return0;
0040 }
获取IP、掩码、MAC及⽹关
获取IP、掩码、MAC和⼴播地址是⽐较容易的,只需要调⽤对应的IOCTL即可。只是⼤家对Linux下的IOCTL可能不太熟悉。却看⽰例代码:
0001void DispNetInfo(const char* szDevName)
0002 {
0003int s = socket(AF_INET, SOCK_DGRAM, 0);
0004if (s < 0)
0005    {
0006        fprintf(stderr, "Create socket failed!errno=%d", errno);
0007return;
0008    }
0009
0010struct 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);
0017if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0)
0018    {
0019return;
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);
0026if (ioctl(s, SIOCGIFADDR, &ifr) < 0)
0027    {
0028        nIP = 0;
0029    }
0030else
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);
0037if (ioctl(s, SIOCGIFBRDADDR, &ifr) < 0)
0038    {
0039        nBroadIP = 0;
0040    }
0041else
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);
0048if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0)
0049    {
0050        nNetmask = 0;
0051    }
0052else
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的源代码以后才知道正确的做法。代码如下: 1  res_init();
2
3for (int i = 0; i < _res.nscount; i++)
4
5        {
6
7struct sockaddr* server = (struct sockaddr*)&_res.nsaddr_list[i];
8
9              printf("Server:  %s\n", inet_ntoa(*(in_addr*)&(server->sa_data[2])));
10
11        }
代码很简单,就不做解释了。
怎么获取⽹关呢?这个稍微有点⿇烦⼀些,不过和获取⽹卡数量相似,都是通过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:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。