1. 程式人生 > >C語言實現:獲取ifconfig相關引數

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等等;