ioctl在socket中的一些用法及示例

-------------------------------------------------------------------
ioctl在socket中的一些用法及示例

函數 : ioctl(int fd, int request, void * arg)
定義 : <sys/ioctl.h>
功能 : 控制I/O設備, 提供了一種得到設備信息和向設備發送控制參數的手段.
參數 : int  fd      文件句柄. 用於socket時, 是socket套接字.
       int  request 函數定義的全部操做. 關於socket的操做, 定義在<linux/sockios.h>文件中.
       void *arg    指針的類型依賴於request參數.
 
如下表格從網上收集了request - arg指針類型的對應關係

類別html

Requestlinux

說明ios

數據類型緩存

 
 
異步

SIOCATMARK 
SIOCSPGRP 
SIOCGPGRPsocket

是否位於帶外標記 
設置套接口的進程ID 或進程組ID 
獲取套接口的進程ID 或進程組ID函數

int 
int 
intui

 
spa

FIONBIN 
FIOASYNC 
FIONREAD 
FIOSETOWN 
FIOGETOWN.net

設置/ 清除非阻塞I/O 標誌 
設置/ 清除信號驅動異步I/O 標誌 
獲取接收緩存區中的字節數 
設置文件的進程ID 或進程組ID 
獲取文件的進程ID 或進程組ID

int 
int 
int 
int 
int

 

SIOCGIFCONF 
SIOCSIFADDR 
SIOCGIFADDR 
SIOCSIFFLAGS 
SIOCGIFFLAGS 
SIOCSIFDSTADDR 
SIOCGIFDSTADDR 
SIOCGIFBRDADDR 
SIOCSIFBRDADDR 
SIOCGIFNETMASK 
SIOCSIFNETMASK 
SIOCGIFMETRIC 
SIOCSIFMETRIC 
SIOCGIFMTU 
SIOCxxx

獲取全部接口的清單 
設置接口地址 
獲取接口地址 
設置接口標誌 
獲取接口標誌 
設置點到點地址 
獲取點到點地址 
獲取廣播地址 
設置廣播地址 
獲取子網掩碼 
設置子網掩碼 
獲取接口的測度 
設置接口的測度 
獲取接口MTU 
(還有不少取決於系統的實現)

struct ifconf 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq 
struct ifreq

ARP

SIOCSARP 
SIOCGARP 
SIOCDARP

建立/ 修改ARP 表項 
獲取ARP 表項 
刪除ARP 表項

struct arpreq 
struct arpreq 
struct arpreq

 

SIOCADDRT 
SIOCDELRT

增長路徑 
刪除路徑

struct rtentry 
struct rtentry

I_xxx

 

 

socket最經常使用到的結構體: struct ifreq 定義在<net/if.h>.(包括struct ifconf/ifr_flags等的定義)

 

1、獲取

如下例程經過ioctl獲取設備"eth0"的IP/掩碼/硬件址

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

#include "net/if.h"
#include "arpa/inet.h"
#include "linux/sockios.h"

int main(int argc,char *argv[])
{
    struct sockaddr_in *addr;
    struct ifreq ifr;
    char*address;
    int sockfd;

    char *name = "eth0";
    if( strlen(name) >= IFNAMSIZ)
        printf("device name is error.\n"), exit(0);
        
    strcpy( ifr.ifr_name, name);
        
    sockfd = socket(AF_INET,SOCK_DGRAM,0);

    //get inet addr
    if( ioctl( sockfd, SIOCGIFADDR, &ifr) == -1)
        printf("ioctl error.\n"), exit(0);

    addr = (struct sockaddr_in *)&(ifr.ifr_addr);
    address = inet_ntoa(addr->sin_addr);

    printf("inet addr: %s\n",address);

    //get Mask
    if( ioctl( sockfd, SIOCGIFNETMASK, &ifr) == -1)
        printf("ioctl error.\n"), exit(0);

    addr = (struct sockaddr_in *)&ifr.ifr_addr;
    address = inet_ntoa(addr->sin_addr);

    printf("Mask: %s\n",address);

    //get HWaddr 
    u_int8_t hd[6];
    if(ioctl(sockfd, SIOCGIFHWADDR, &ifr) == -1)
        printf("hwaddr error.\n"), exit(0);

    memcpy( hd, ifr.ifr_hwaddr.sa_data, sizeof(hd));
    printf("HWaddr: %02X:%02X:%02X:%02X:%02X:%02X\n", hd[0], hd[1], hd[2], hd[3], hd[4], hd[5]);
    
    exit(0);
}

  

 

 2、設置

如下例程設置eth0的IP地址.

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

#include "net/if.h"
#include "arpa/inet.h"
#include "linux/sockios.h"

int main(int argc,char *argv[])
{
    char *dev = "eth0";
    char *ip = "192.168.1.252";
    
    struct ifreq ifr;
    if( strlen(dev) >= IFNAMSIZ)
        printf("device name error.\n"), exit(0);
    else
        strcpy( ifr.ifr_name, dev);
    
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);

    //get inet addr
    if( ioctl( sockfd, SIOCGIFADDR, &ifr) == -1)
        printf("ioctl error.\n"), exit(0);
    
    struct sockaddr_in *addr = (struct sockaddr_in *)&(ifr.ifr_addr);
    char * address = inet_ntoa(addr->sin_addr);

    printf("current inet addr: %s\n",address);

    //set inet addr
    struct sockaddr_in *p = (struct sockaddr_in *)&(ifr.ifr_addr);

    p->sin_family = AF_INET;
    inet_aton( ip, &(p->sin_addr));

    if( ioctl( sockfd, SIOCSIFADDR, &ifr) == -1)
     printf("ioctl error.\n"), exit(0);
    else    
        printf("change inet addr to: %s\n", ip);

    //any OS need active dev.
    /*ifr.ifr_flags |= IFF_UP;
    if( ioctl( sockfd, SIOCSIFFLAGS, &ifr) == -1)
        printf("active fault.\n"), exit(0);
    else
        printf("%s[%s] is working...\n", dev, ip);
    */
        
    close(sockfd);
    exit(1);
    //end
}

  

屏蔽的代碼用於設置IP後, 激活新設置. 多數系統不須要這步操做. 
並且這步僅做演示. 真實使用的時候, 至少應該
1. 獲取當前ifr.ifr_flags
2. ifr.ifr_flags |= IFF_UP;

以上是ioctl的一些示例, 實戰中靈活使用、觸類旁通.

相關文章
相關標籤/搜索