首页 > 代码库 > ioctl获取网络接口信息

ioctl获取网络接口信息

linux下网络程序经常在启动执行后使用ioctl获取主机的全部网络接口信息,

例如接口地址、是否支持广播,是否支持多播等。


函数原型

#include <sys/ioctl.h>
int ioctl(int d, int request, ...);返回值:成功返回0,出错返回-1 

常见选项
SIOCGIFCONF 获取所有接口的列表
SIOCGIFBRDADDR 获取广播地址
SIOCGIFMTU  获取mtu


linux下使用ioctl操作网络接口,需要用到两个结构体

ifconf用来保存所有网络接口信息,结构体为:

struct ifconf
  {
    int	ifc_len;			/* 存放接口信息所需的长度.  */
    union
      {
	__caddr_t ifcu_buf;             /* 存放接口信息的地址 */
	struct ifreq *ifcu_req;
      } ifc_ifcu;
  };
# define ifc_buf	ifc_ifcu.ifcu_buf	
# define ifc_req	ifc_ifcu.ifcu_req

ifreq用来保存某个接口的信息

struct ifreq
  {
# define IFHWADDRLEN	6
# define IFNAMSIZ	IF_NAMESIZE
    union
      {
	char ifrn_name[IFNAMSIZ];	/* 接口名字, e.g. "en0".*/
      } ifr_ifrn;

    union
      {
	struct sockaddr ifru_addr;      /* 接口的IP地址 */
	struct sockaddr ifru_dstaddr;
	struct sockaddr ifru_broadaddr; /* 接口的广播地址 */
	struct sockaddr ifru_netmask;   /* 接口的子网掩码 */
	struct sockaddr ifru_hwaddr;    /* 接口的mac地址 */
	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)

操作:
1.通过ioctl获得本地所有接口信息存放在ifconf结构中
2.从ifcong中获得某个ifreq的接口信息
其中:
ifc_len:存放所有接口信息的缓冲区长度
ifc_buf:存放接口信息的缓冲区

首先对ifconf的ifc_len和ifc_buf初始化
用ioctl获取所有接口信息,之后ifc_len内存放实际获得的接口信息总长度,信息存放在ifc_buf中

实例:

#include <net/if.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>


using namespace std;

int main()
{	
	//得到套接字描述符
	int sockfd;		
	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
	{
		perror("socket error");
		exit(-1);
	}
	
	struct ifconf ifc;
	caddr_t buf;
	int len = 100;
	
	//初始化ifconf结构
	ifc.ifc_len = 1024;
	if ((buf = (caddr_t)malloc(1024)) == NULL)
	{
		cout << "malloc error" << endl;
		exit(-1);
	}
	ifc.ifc_buf = buf; 
	
	//获取所有接口信息
	if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0)
	{
		perror("ioctl error");
		exit(-1);
	}
	
	//遍历每一个ifreq结构
	struct ifreq *ifr;
	struct ifreq ifrcopy;
	ifr = (struct ifreq*)buf;
	for(int i = (ifc.ifc_len/sizeof(struct ifreq)); i>0; i--)
	{
		//接口名
		cout << "interface name: "<< ifr->ifr_name << endl;
		//ipv4地址
		cout << "inet addr: " 
			 << inet_ntoa(((struct sockaddr_in*)&(ifr->ifr_addr))->sin_addr)
			 << endl;
		
		//获取广播地址
		ifrcopy = *ifr;
		if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0)
		{
			perror("ioctl error");
			exit(-1);
		}
		cout << "broad addr: "
			 << inet_ntoa(((struct sockaddr_in*)&(ifrcopy.ifr_addr))->sin_addr)
			 << endl;
		//获取mtu
		ifrcopy = *ifr;
		if (ioctl(sockfd, SIOCGIFMTU, &ifrcopy) < 0)
		{
			perror("ioctl error");
			exit(-1);
		}
		cout << "mtu: " << ifrcopy.ifr_mtu << endl;
		cout << endl;
		ifr++;
	}
	
	return 0;
}