1. 程式人生 > >linux下使用ioctl() 獲取本機mac地址、ip地址等等

linux下使用ioctl() 獲取本機mac地址、ip地址等等

       在linux下,我們知道可以通過ifconfig獲取mac地址和ip地址等相關資訊,但是如果要使用gcc程式實現的話,我們就需要使用到系統所提供的一個函式ioctl(),iotec函式是對裝置的i/o通道進行管理的函式。由於這個函式用途比較多,如果要學習可以參照官方的說明。

       第一步,我們需要定義幾個變數:

    struct ifreq *ifrp,ifr;
    struct ifconf ifc;
    char buffer[720],name[16];
    int socketfd,error,flags,len,space=0;

       其中,struct ifreq 就是用來儲存返回的介面相關資訊的結構體,由於電腦可能有多個硬體藉口,因此我們使用指標來儲存返回的結構體陣列。struct ifconf變數是用來儲存ioctl()函式返回結果的。因為我們是要獲取mac地址的相關信
//
//  main.cpp
//  arp
//
//  Created by Allen on 14-4-7.
//  Copyright (c) 2014年 Allen. All rights reserved.
//
#include <iostream>


#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/sysctl.h>

#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_types.h>

#include <netinet/in.h>
#include <netinet/in_var.h>
#include <arpa/inet.h>

#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//讀取本機mac地址的方法
int main()
{
    struct ifreq *ifrp,ifr;
    struct ifconf ifc;
    char buffer[720],name[16];
    int socketfd,error,flags,len,space=0;
    ifc.ifc_len=sizeof(buffer);
    len=ifc.ifc_len;
    
    ifc.ifc_buf=buffer;
    
    socketfd=socket(AF_INET,SOCK_DGRAM,0);//建立一個socket
    
    if((error=ioctl(socketfd,SIOCGIFCONF,&ifc))<0)//使用SIOCGIFCONF獲得所有介面的清單
    {
        perror("ioctl faild");
        exit(1);
    }
    
    if(ifc.ifc_len<=len)//buffer 的大小如果沒有問題
    {
        ifrp=ifc.ifc_req;//將獲取的所有藉口的所有清單傳到ifrp指標上。
        do
        {
            struct sockaddr *sa=&ifrp->ifr_addr;//定義sockaddr物件
            strcpy(ifr.ifr_name,ifrp->ifr_name);
            if(strcmp(ifrp->ifr_name,name)!=0){
                strcpy(name,ifrp->ifr_name);
                printf("%s:",ifrp->ifr_name);// 列印介面名
                if(!ioctl(socketfd,SIOCGIFFLAGS,&ifr))//get ifnet flags
                {
                    flags=ifr.ifr_flags;
                    printf("flags=%x<",flags<<16);
                    if(ifr.ifr_flags&IFF_UP){
                        printf("UP,");
                    }
                    else{
                        printf("DOWN");
                    }
                    if(ifr.ifr_flags&IFF_BROADCAST){
                        printf("BOROADCAST,");
                    }
                    if(ifr.ifr_flags&IFF_POINTOPOINT){
                        printf("POINTOPOINT,");
                    }
                    if(ifr.ifr_flags&IFF_LOOPBACK){
                        printf("LOOPBACK,");
                    }
                    if(ifr.ifr_flags&IFF_RUNNING){
                        printf("RUNNING,");
                    }
                    if(ifr.ifr_flags&IFF_SIMPLEX){
                        printf("SIMPLEX,");
                    }
                    if(ifr.ifr_flags&IFF_MULTICAST){
                        printf("MULTICAST");
                    }
                    printf(">;\n");
                }
                if(!ioctl(socketfd,SIOCGIFADDR,&ifr)){
                    printf("     inet %s",inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
                }
                if(!ioctl(socketfd,SIOCGIFNETMASK,&ifr)){
                    printf(" netmask %s",inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
                }
                if(!ioctl(socketfd,SIOCGIFBRDADDR,&ifr)){
                    printf(" broadcast %s\n",inet_ntoa(((struct sockaddr_in *)&ifr.ifr_broadaddr)->sin_addr));
                }
                if(((struct sockaddr_dl *)sa)->sdl_type==IFT_ETHER)
                    printf("     ether %s\n",ether_ntoa((struct ether_addr *)LLADDR((struct sockaddr_dl *)sa)));
                //printf("types %x\n",((struct sockaddr_dl *)sa)->;sdl_type);
                
            }
            ifrp=(struct ifreq*)(sa->sa_len+(caddr_t)&ifrp->ifr_addr);
            space+=(int)sa->sa_len+sizeof(ifrp->ifr_name);
        }
        while(space<ifc.ifc_len);
        
    }
    exit(0);
}

息,那麼按照ioctl函式穿慘的要求,第一個是socketfd,第二個是巨集SIOCGIFCONF,返回值是所有介面的清單儲存在ifc中。之後使用ifreq指標指向ifc中的ifc_req陣列。之後使用一個迴圈來分別獲取每個介面的引數。