C语言在linux下获取网络参数

总结一下,今天学习的关于通过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和子网掩码的过程。。。。


以上转载的为http://blog.chinaunix.net/uid-25100840-id-2377089.html,如有疑问请联系我。

此外,我还看到更全的代码:

ifconfig是我们查看/设定网口状态常用的命令,其实这个命令就是对一些系统函数的封装,通过对struct ifreq的修改,我们可以很轻易地设定网口状态,获取网口状态。

这个结构体位于<net/if.h>头文件中,打开去看看吧,对照着英文注释,很容易找到自己想要的东西。而网卡相关的一些ioctl操作, 也就是用于查询/修改状态的标记位,都在<linux/sockios.h>中,很清晰的,找份源码看看吧。下面是一个小示例,演示了获取信息的过程,如果有需要,也可以启用那个修改状态的函数,注意,修改状态标记位的时候,需要用到超级用户的权限。

/**
 * \file getifstat.c
 * \author  wzj
 * \brief 访问这个struct ifconf 修改,查询状态
 * \version  
 * \note   
 * \date: 2012年08月11日星期六22:55:25
 */   
#include <net/if.h>       /* for ifconf */  
#include <linux/sockios.h>    /* for net status mask */  
#include <netinet/in.h>       /* for sockaddr_in */  
#include <sys/socket.h>  
#include <sys/types.h>  
#include <sys/ioctl.h>  
#include <stdio.h>  
#include <string.h>
 
#define MAX_INTERFACE   (16)  
 
void port_status(unsigned int flags);  
 
/* set == 0: do clean , set == 1: do set! */  
int set_if_flags(char *pif_name, int sock, int status, int set)  
{  
    struct ifreq ifr;  
    int ret = 0;  
      
    strncpy(ifr.ifr_name, pif_name, strlen(pif_name) + 1);  
    ret = ioctl(sock, SIOCGIFFLAGS, &ifr);  
    if(ret)  
        return -1;  
    /* set or clean */    
    if(set)  
        ifr.ifr_flags |= status;  
    else   
        ifr.ifr_flags &= ~status;  
    /* set flags */  
    ret = ioctl(sock, SIOCSIFFLAGS, &ifr);  
    if(ret)  
        return -1;  
      
    return 0;  
}  
 
int get_if_info(int fd)  
{  
    struct ifreq buf[MAX_INTERFACE];      
    struct ifconf ifc;  
    int ret = 0;  
    int if_num = 0;  
 
    ifc.ifc_len = sizeof(buf);  
    ifc.ifc_buf = (caddr_t) buf;  
      
    ret = ioctl(fd, SIOCGIFCONF, (char*)&ifc);  
    if(ret)  
    {  
        printf("get if config info failed");  
        return -1;  
    }  
    /* 网口总数 ifc.ifc_len 应该是一个出入参数 */      
    if_num = ifc.ifc_len/sizeof(struct ifreq);  
    printf("interface num is interface = %d\n", if_num);  
    while(if_num-- > 0)  
    {  
        printf("net device: %s\n", buf[if_num].ifr_name);     
        /* 获取第n个网口信息 */  
        ret = ioctl(fd, SIOCGIFFLAGS, (char*)&buf[if_num]);  
        if(ret)  
            continue;  
 
        /* 获取网口状态 */  
        port_status(buf[if_num].ifr_flags);  
          
        /* 获取当前网卡的ip地址 */  
        ret = ioctl(fd, SIOCGIFADDR, (char*)&buf[if_num]);  
        if(ret)  
            continue;  
        printf("IP address is: \n%s\n", (char *)inet_ntoa(((struct sockaddr_in *)(&buf[if_num].ifr_addr))->sin_addr));  
 
        /* 获取当前网卡的mac */  
        ret = ioctl(fd, SIOCGIFHWADDR, (char*)&buf[if_num]);  
        if(ret)  
            continue;  
 
        printf("%02x:%02x:%02x:%02x:%02x:%02x\n\n",  
            (unsigned char)buf[if_num].ifr_hwaddr.sa_data[0],  
            (unsigned char)buf[if_num].ifr_hwaddr.sa_data[1],  
            (unsigned char)buf[if_num].ifr_hwaddr.sa_data[2],  
            (unsigned char)buf[if_num].ifr_hwaddr.sa_data[3],  
            (unsigned char)buf[if_num].ifr_hwaddr.sa_data[4],  
            (unsigned char)buf[if_num].ifr_hwaddr.sa_data[5]  
            );  
    }  
}  
 
void port_status(unsigned int flags)  
{  
    if(flags & IFF_UP)    
    {  
        printf("is up\n");        
    }  
    if(flags & IFF_BROADCAST)     
    {  
        printf("is broadcast\n");     
    }  
    if(flags & IFF_LOOPBACK)      
    {  
        printf("is loop back\n");     
    }  
    if(flags & IFF_POINTOPOINT)   
    {  
        printf("is point to point\n");    
    }  
    if(flags & IFF_RUNNING)   
    {  
        printf("is running\n");   
    }  
    if(flags & IFF_PROMISC)   
    {  
        printf("is promisc\n");   
    }  
}  
 
int main()  
{  
    int fd;  
 
    fd = socket(AF_INET, SOCK_DGRAM, 0);  
    if(fd > 0)  
    {  
        get_if_info(fd);  
        close(fd);  
    }  
 
    return 0;  
}

以上代码我已经测试,而且做了点点修改,源地址:http://blog.csdn.net/joker0910/article/details/7855998

还有一种方法:

用system调用ifconfig命令,再用程序获取shell下的字符串,使用方法见http://blog.chinaunix.net/uid-23381466-id-58497.html;

学习中,记录下来

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值