總結一下,今天學習的關於通過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<sys_nic_count;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和子網掩碼的過程。。。。