C語言實現:獲取ifconfig相關引數
總結一下,今天學習的關於通過socket,ioctl來獲得ip,netmask等資訊,其中很多內容參照了很多網上的資訊,我會一一列出的
我用的這個函式,就是下面這個函式,其中的有一些全域性變數,很好懂,也就不多做解釋了
一、下面對這個函式進行註解一下:
int get_nic_IP_Address()//獲取各網絡卡IP地址、子網掩碼
{
struct ifreq ifreq; //宣告一個struct ifreq結構體(這個結構體中有很多重要的引數,具體可以參照第二的補充)
int sock;
int i;
int tmpint;
read_dev(); //這個函式的功能是獲得網絡卡名字(儲存在下面提到的sys_nic_ip[][]陣列中)並計算網絡卡總數(就是下面的sys_nic_count)
for (i=0;i {
if((sock=socket(AF_INET,SOCK_STREAM,0))<0){ //建立一個套接字
perror("socket");
return ;
}
strcpy(ifreq.ifr_name,sys_nic_name[i]); //把網絡卡名字複製到ifreq結構體中的name變數(感覺這個地方是必須的)
if(ioctl(sock,SIOCGIFADDR,&ifreq)<0) { //這裡涉及ioctl函式對於網路檔案的控制(下面會介紹)
sprintf(sys_nic_ip[i],"Not set");
} else {
sprintf(sys_nic_ip[i],"%d.%d.%d.%d", //把ip地址提取出來,儲存(理解一下socketaddr_in和socketaddr的關係)
(unsigned char)ifreq.ifr_addr.sa_data[2],
(unsigned char)ifreq.ifr_addr.sa_data[3],
(unsigned char)ifreq.ifr_addr.sa_data[4],
(unsigned char)ifreq.ifr_addr.sa_data[5]);
}
if(ioctl(sock,SIOCGIFNETMASK,&ifreq)<0) { //我的理解是這個地方用SIOCGIFNETMASK,那麼ifreq中原本是存的ip地址,現在存成了子網掩碼了。。
sprintf(sys_nic_mask[i],"Not set"); //把子網掩碼提取出來(但得到的只是超網的劃分方式就是/xx)
} else {
sprintf(sys_nic_mask[i],"%d",
Count((unsigned char)ifreq.ifr_netmask.sa_data[2])+
Count((unsigned char)ifreq.ifr_netmask.sa_data[3])+
Count((unsigned char)ifreq.ifr_netmask.sa_data[4])+
Count((unsigned char)ifreq.ifr_netmask.sa_data[5]));
}
}
}
列出上面最後呼叫函式(Count())和一些全副變數:
char sys_nic_ip[20][20];//各網絡卡IP
char sys_nic_mask[20][20];//各網絡卡子網掩碼"/xx"
int countTable[256] =
{
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
int Count(int v)
{
return countTable[v];
}
應該理解了吧。。。挺經典的。。。不過網上的貌似就有一個版本。。。很是氣惱
二、對涉及的知識點進行補充
1.struct ifreq {
char ifr_name[IFNAMSIZ];
union
{
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
short int ifru_flags;
int ifru_ivalue;
int ifru_mtu;
struct ifmap ifru_map;
char ifru_slave[IFNAMSIZ]; /* Just fits the size */
char ifru_newname[IFNAMSIZ];
__caddr_t ifru_data;
} ifr_ifru;
};
# define ifr_name ifr_ifrn.ifrn_name /* interface name */
# define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
# define ifr_addr ifr_ifru.ifru_addr /* address */
# define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */
# define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
# define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
# define ifr_flags ifr_ifru.ifru_flags /* flags */
# define ifr_metric ifr_ifru.ifru_ivalue /* metric */
# define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
# define ifr_map ifr_ifru.ifru_map /* device map */
# define ifr_slave ifr_ifru.ifru_slave /* slave device */
# define ifr_data ifr_ifru.ifru_data /* for use by interface */
# define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */
# define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */
# define ifr_qlen ifr_ifru.ifru_ivalue /* queue length */
# define ifr_newname ifr_ifru.ifru_newname /* New name */
# define _IOT_ifreq _IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0)
# define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0)
# define _IOT_ifreq_int _IOT(_IOTS(char),IFNAMSIZ,_IOTS(int),1,0,0)
2.ioctl 函式 (在網路中的作用)
關於這個網路相關的請求,就是ioctl在這裡面起的作用和各個引數的作用。。。可以參照這個網頁,講解的很詳細:
http://www.iteye.com/topic/309442
本例中用的2個ioctl控制函式。。上面已經解釋很清楚了
3.關於socketaddr_in和socketaddr的關係,下面貼出具體的定義:
struct sockaddr_in
{
short int sin_family; /* 地址族 */
unsigned short int sin_port; /* 埠號 */
struct in_addr sin_addr; /* IP地址 */
unsigned char sin_zero[8]; /* 填充0 以保持與struct sockaddr同樣大小 */
};
struct sockaddr
{
unsigned short sa_family; /* 地址族, AF_xxx */
char sa_data[14]; /* 14 位元組的協議地址 */
};
比較一下,會發現長度一樣,所以這2個可以通用的,不過要進行型別轉換,比較一下就得出了為什麼上面程式中可以用:
(unsigned char)ifreq.ifr_addr.sa_data[2],這種形式了,還是解釋一下吧:這個ifr_addr是一個struct sockaddr結構體。它其中的sa_date[2]是不是照著上面sockaddr_in中的sin_add(也就是ip地址呢),該明白了吧。。。。
總結:通過這個函式,可以很好的理解怎麼得到ip和子網掩碼的過程。。。。
三、例項
static int get_mac(char* mac,char* brifc)
{
struct ifreq tmp;
int sock_mac;
char mac_addr[32]={0};
sock_mac = socket(AF_INET, SOCK_STREAM, 0);
if( sock_mac == -1)
{
perror("create socket fail\n");
return -1;
}
memset(&tmp,0,sizeof(tmp));
strncpy(tmp.ifr_name,brifc,sizeof(tmp.ifr_name)-1 );
if( (ioctl( sock_mac, SIOCGIFHWADDR, &tmp)) < 0 )
{
printf("mac ioctl error\n");
return -1;
}
sprintf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x",\
(unsigned char)tmp.ifr_hwaddr.sa_data[0],
(unsigned char)tmp.ifr_hwaddr.sa_data[1],
(unsigned char)tmp.ifr_hwaddr.sa_data[2],
(unsigned char)tmp.ifr_hwaddr.sa_data[3],
(unsigned char)tmp.ifr_hwaddr.sa_data[4],
(unsigned char)tmp.ifr_hwaddr.sa_data[5]
);
close(sock_mac);
memcpy(mac,mac_addr,strlen(mac_addr));
return 0;
}
注:引數char* brifc為介面名,如:br-lan、br0等等;