unix網絡編程——ioctl 函數的用法詳解

轉載自:unix網絡編程——ioctl 函數的用法詳解html


 

[置頂] unix網絡編程——ioctl 函數的用法詳解

分類: 2.2. 網絡   3833人閱讀  評論(2)  收藏  舉報

目錄(?)[+]linux

1.介紹

Linux網絡程序與內核交互的方法是經過ioctl來實現的,ioctl與網絡協議棧進行交互,可獲得網絡接口的信息,網卡設備的映射屬性和配置網絡接口.而且還可以查看,修改,刪除ARP高速緩存的信息,因此,咱們有必要了解一下ioctl函數的具體實現.編程

2.函數說明

SYNOPSIS
       #include <sys/ioctl.h>

       int ioctl(int d, int request, ...);

DESCRIPTION
       The  ioctl()  function  manipulates the underlying device parameters of
       special files.  In particular, many operating characteristics of  char-
       acter  special  files  (e.g., terminals) may be controlled with ioctl()
       requests.  The argument d must be an open file descriptor.

       The second argument is a  device-dependent  request  code.   The  third
       argument  is  an  untyped  pointer  to memory.  It’s traditionally char
       *argp (from the days before void * was valid C), and will be  so  named
       for this discussion.

       An  ioctl()  request  has  encoded  in it whether the argument is an in
       parameter or out parameter, and the size of the argument argp in bytes.
       Macros and defines used in specifying an ioctl() request are located in
       the file <sys/ioctl.h>.

RETURN VALUE
       Usually, on success zero is returned.  A few ioctl() requests  use  the
       return  value as an output parameter and return a non-negative value on
       success.  On error, -1 is returned, and errno is set appropriately.

數組

3.參數說明

類別緩存

Request網絡

說明數據結構

數據類型app

框架

異步

SIOCATMARK

SIOCSPGRP

SIOCGPGRP

是否位於帶外標記

設置套接口的進程ID或進程組ID

獲取套接口的進程ID或進程組ID

int

int

int

FIONBIN

FIOASYNC

FIONREAD

FIOSETOWN

FIOGETOWN

設置/清除非阻塞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

   

4.相關數據結構

  1. <h2><a name="t4"></a>(1)網絡接口請求結構ifreq</h2>  
  2. struct ifreq {  
  3. #define IFHWADDRLEN 6 //6個字節的硬件地址,即MAC  
  4.     union {  
  5.         char ifrn_name[IFNAMESIZ]; //網絡接口名稱  
  6.     }ifr_ifrn;  
  7.     union {  
  8.         struct sockaddr ifru_addr; //本地IP地址  
  9.         struct sockaddr ifru_dstaddr;//目標IP地址  
  10.         struct sockaddr ifru_broadaddr;//廣播IP地址  
  11.         struct sockaddr ifru_netmask;//本地子網掩碼地址  
  12.         struct sockaddr ifru_hwaddr;//本地MAC地址  
  13.         short ifru_flags;//網絡接口標記  
  14.         int ifru_ivalue;//不一樣的請求含義不一樣  
  15.         struct ifmap ifru_map;//網卡地址映射  
  16.         int ifru_mtu;//最大傳輸單元  
  17.         char ifru_slave[IFNAMSIZ];//佔位符  
  18.         char ifru_newname[IFNAMSIZE];//新名稱  
  19.         void __user* ifru_data;//用戶數據  
  20.         struct if_settings ifru_settings;//設備協議設置  
  21.     }ifr_ifru;  
  22. }  
  23. #define ifr_name ifr_ifrn.ifrn_name;//接口名稱  
  24. #define ifr_hwaddr ifr_ifru.ifru_hwaddr;//MAC  
  25. #define ifr_addr ifr_ifru.ifru_addr;//本地IP  
  26. #define ifr_dstaddr ifr_ifru.dstaddr;//目標IP  
  27. #define ifr_broadaddr ifr_ifru.broadaddr;//廣播IP  
  28. #define ifr_netmask ifr_ifru.ifru_netmask;//子網掩碼  
  29. #define ifr_flags ifr_ifru.ifru_flags;//標誌  
  30. #define ifr_metric ifr_ifru.ifru_ivalue;//接口側度  
  31. #define ifr_mtu ifr_ifru.ifru_mtu;//最大傳輸單元  
  32. #define ifr_map ifr_ifru.ifru_map;//設備地址映射  
  33. #define ifr_slave ifr_ifru.ifru_slave;//副設備  
  34. #define ifr_data ifr_ifru.ifru_data;//接口使用  
  35. #define ifr_ifrindex ifr_ifru.ifru_ivalue;//網絡接口序號  
  36. #define ifr_bandwidth ifr_ifru.ifru_ivalue;//鏈接帶寬  
  37. #define ifr_qlen ifr_ifru.ifru_ivalue;//傳輸單元長度  
  38. #define ifr_newname ifr_ifru.ifru_newname;//新名稱  
  39. #define ifr_seeting ifr_ifru.ifru_settings;//設備協議設置  
  40. 若是想得到網絡接口的相關信息,就傳入ifreq結構體.  
  41.   
  42. <h2><a name="t5"></a>(2)網卡設備屬性ifmap</h2>  
  43. struct ifmap { //網卡設備的映射屬性  
  44.     unsigned long mem_start;//開始地址  
  45.     unsigned long mem_end;//結束地址  
  46.     unsigned short base_addr;//基地址  
  47.     unsigned char irq;//中斷號  
  48.     unsigned char dma;//DMA  
  49.     unsigned char port;//端口  
  50. }  
  51.   
  52. <h2><a name="t6"></a>(3)網絡配置接口ifconf</h2>  
  53. struct ifconf { //網絡配置結構體是一種緩衝區  
  54.     int ifc_len;//緩衝區ifr_buf的大小  
  55.     union {  
  56.         char__user *ifcu_buf; //繪衝區指針  
  57.         struct ifreq__user* ifcu_req;//指向ifreq指針  
  58.     }ifc_ifcu;  
  59. };  
  60. #define ifc_buf ifc_ifcu.ifcu_buf;//緩衝區地址  
  61. #define ifc_req ifc_ifcu.ifcu_req;//ifc_req地址  
  62.   
  63. <h2><a name="t7"></a>(4)ARP高速緩存操做arpreq</h2>  
  64. /**  
  65.  ARP高速緩存操做,包含IP地址和硬件地址的映射表  
  66.  操做ARP高速緩存的命令字 SIOCDARP,SIOCGARP,SIOCSARP分別是刪除ARP高速緩存的一條記錄,得到ARP高速緩存的一條記錄和修改ARP高速緩存的一條記錄  
  67.  struct arpreq{  
  68.  struct sockaddr arp_pa;//協議地址  
  69.  struct sockaddr arp_ha;//硬件地址  
  70.  int arp_flags;//標記  
  71.  struct sockaddr arp_netmask;//協議地址的子網掩碼  
  72.  char arp_dev[16];//查詢網絡接口的名稱  
  73.  }  


5. 相關代碼例子

  1. <pre name="code" class="cpp">#include <sys/types.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <unistd.h>  
  5. #include <sys/ioctl.h>  
  6. #include <sys/socket.h>  
  7. #include <netdb.h>  
  8. #include <string.h>  
  9. #include <fcntl.h>  
  10. #include <net/if.h>  
  11. #include <string.h>  
  12.   
  13. int main(int argc, char*argv[]) {  
  14.     int s,sv6;  
  15.     int err;  
  16.     s = socket(AF_INET, SOCK_DGRAM, 0);  
  17.     if (s < 0) {  
  18.         perror("socket error");  
  19.         return -1;  
  20.     }  
  21.   
  22. //傳入網絡接口序號,得到網絡接口的名稱  
  23.     struct ifreq ifr;  
  24.     int ia = sizeofstruct ifreq );  
  25.     ia = sizeof(struct sockaddr);  
  26.    ia = 1;   err = 0;  
  27.     bzero(&ifr, sizeof(struct ifreq));  
  28.     while (err != -1) {  
  29.   
  30.         ifr.ifr_ifindex = ia++; //得到第2個網絡接口的名稱  
  31.         err = ioctl(s, SIOCGIFNAME, &ifr);  
  32.         if (-1 == err) {  
  33.             perror("index error");  
  34.         } else { //10111111 11111111 11101101 11101000  
  35.             char ipbuf[255];  
  36.             inet_ntop(AF_INET,  
  37.                     &((struct sockaddr_in*) &(ifr.ifr_ifru.ifru_addr))->sin_addr,  
  38.                     ipbuf, sizeof(ipbuf));  
  39.             printf("the %dst interface is:%s \t addr:%s\n", ifr.ifr_ifindex,  
  40.                     ifr.ifr_name, ipbuf);  
  41.         }  
  42.     }  
  43. //傳入網絡接口名稱,得到標誌  
  44.     bzero(&ifr,sizeof(struct ifreq));  
  45.     memcpy(ifr.ifr_name, "eth0", 5);  
  46.     err = ioctl(s, SIOCGIFFLAGS, &ifr);  
  47.     if (!err) {  
  48.         printf("SIOCGIFFLAGS:%d\n", ifr.ifr_flags);  
  49.     }  
  50.   
  51. //得到MTU和MAC  
  52.     bzero(&ifr,sizeof(struct ifreq));  
  53.     memcpy(ifr.ifr_name, "eth0", 5);  
  54.     err = ioctl(s, SIOCGIFMTU, &ifr);  
  55.     if (err!=-1) {  
  56.         printf("SIOCGIFMTU:%d\n", ifr.ifr_mtu);  
  57.     }else  
  58.         perror("ioctl:");  
  59. //得到MAC地址  
  60.     bzero(&ifr,sizeof(struct ifreq));  
  61.     memcpy(ifr.ifr_name, "eth0", 5);  
  62.  //   ifr.ifr_ifindex = 1;  
  63.     err = ioctl(s, SIOCGIFHWADDR, &ifr);  
  64.     if (-1!=err) {  
  65.         unsigned char* hw = ifr.ifr_ifru.ifru_hwaddr.sa_data;  
  66.         printf("SIOCGIFHWADDR:%02x:%02x:%02x:%02x:%02x:%02x\n", hw[0], hw[1],  
  67.                 hw[2], hw[3], hw[4], hw[5]);  
  68.     }else  
  69.         perror("ioctl:");  
  70. //得到網卡映射參數 命令字SIOCGIFMAP  
  71.   
  72.     err = ioctl(s, SIOCGIFMAP, &ifr);  
  73.     if (!err) {  
  74.         printf(  
  75.                 "SIOCGIFMAP,mem_start:%d,mem_end:%d,base_addr:%d,ifr_map:%d,dma:%d,port:%d\n",  
  76.                 ifr.ifr_map.mem_start, ifr.ifr_map.mem_end,  
  77.                 ifr.ifr_map.base_addr, ifr.ifr_map.irq, ifr.ifr_map.dma,  
  78.                 ifr.ifr_map.port);  
  79.     }  
  80. //得到網卡序號  
  81.     err = ioctl(s, SIOCGIFINDEX, &ifr);  
  82.     if (!err) {  
  83.         printf("SIOCGIFINDEX:%d\n", ifr.ifr_ifindex);  
  84.     }  
  85. //獲取發送隊列的長度  
  86.     err = ioctl(s, SIOCGIFTXQLEN, &ifr);  
  87.     if (!err) {  
  88.         printf("SIOCGIFTXQLEN:%d\n", ifr.ifr_qlen);  
  89.     }  
  90. //獲取網絡接口IP  
  91.     bzero(&ifr,sizeof(struct ifreq));  
  92.     memcpy(ifr.ifr_name, "eth0", 5);  
  93.  //   ifr.ifr_ifru.ifru_ivalue = 2;  
  94.     struct sockaddr_in *sin = (struct sockaddr_in*) &ifr.ifr_addr; //保存的是二進制IP  
  95.     char ip[16]; //字符數組,存放字符串  
  96.     memset(ip, 0, 16);  
  97.     err = ioctl(s, SIOCGIFADDR, &ifr);  
  98.     if (!err) {  
  99.         inet_ntop(AF_INET, &sin->sin_addr.s_addr, ip, 16); //轉換的字符串保存到ip數組中,第二個參數是要轉換的二進制IP指針,第三個參數是轉換完成存放IP的緩衝區,最後一個參數是緩衝區的長度  
  100.         printf("SIOCGIFADDR:%s\n", ip);  
  101.     }  
  102.   
  103. //查詢目標IP地址  
  104.   
  105.     err = ioctl(s, SIOCGIFDSTADDR, &ifr);  
  106.     if (!err) {  
  107.         inet_ntop(AF_INET, &sin->sin_addr.s_addr, ip, 16);  
  108.         printf("SIOCGIFDSTADDR:%s\n", ip);  
  109.     }  
  110. //查詢子網掩碼  
  111.     bzero(&ifr,sizeof(struct ifreq));  
  112.     memcpy(ifr.ifr_name, "eth0", 5);  
  113.     err = ioctl(s, SIOCGIFNETMASK, &ifr);  
  114.     if (!err) {  
  115.         inet_ntop(AF_INET, &sin->sin_addr.s_addr, ip, 16);  
  116.         printf("SIOCGIFNETMASK:%s\n", ip);  
  117.     }  
  118. /* 
  119. //設置IP地址,設置網絡接口 
  120.     inet_pton(AF_INET, "222.27.253.108", &sin->sin_addr.s_addr); //將字符串IP轉換成二進制 
  121.     err = ioctl(s, SIOCSIFADDR, &ifr); //發送設置本機ip地址請求命令 
  122.     if (!err) { 
  123.         printf("check IP-----"); 
  124.         memset(&ifr, 0, sizeof(ifr)); 
  125.         memcpy(ifr.ifr_name, "eth0", 5); 
  126.         ioctl(s, SIOCGIFADDR, &ifr); 
  127.         inet_ntop(AF_INET, &sin->sin_addr.s_addr, ip, 16); 
  128.         printf("%s\n", ip); 
  129.     }*/  
  130. //獲得接口的廣播地址  
  131.     memset(&ifr, 0, sizeof(ifr));  
  132.     memcpy(ifr.ifr_name, "eth0", 5);  
  133.     ioctl(s, SIOCGIFBRDADDR, &ifr);  
  134.     struct sockaddr_in *broadcast = (struct sockaddr_in*) &ifr.ifr_broadaddr;  
  135. //轉換成字符串  
  136.     inet_ntop(AF_INET, &broadcast->sin_addr.s_addr, ip, 16); //inet_ntop將二進制IP轉換成點分十進制的字符串  
  137.     printf("BROADCAST IP:%s\n", ip);  
  138.     close(s);  
  139. }  
  140. </pre><br>  
  141. <pre></pre>  
  142. <br>  
  143. <h1><a name="t9"></a>6.內核主要函數調用框架</h1>  
  144. <p></p>  
  145. <p>內核實現ioctl()函數的是sys_ioctl(),在內核中主要調用框架圖以下,它清晰地給咱們展現ioctl的控制傳遞框架,咱們接下來的內容將根據此圖向你們作詳細的解釋:</p>  
  146. <p><img src="http://img.my.csdn.net/uploads/201211/26/1353937655_1774.jpg" alt=""><br>  
  147. </p>  
  148. <p><br>  
  149. </p>  
  150. <h1><a name="t10"></a>7.小結</h1>  
  151. <p>      本文介紹了ioctrl 主要的用法,固然它還有不少用法,之後會繼續追加的,該如函數的用法,主要就是其對應的request列表的用法,便是該函數的第二個參數的用法</p>  
  152. <p><br>  
  153. </p>  
  154. <p>參考: UNIX 網絡編程</p>  
  155. <p><a href="http://blog.163.com/jlz_325/blog/static/19174000920126893245653/">http://blog.163.com/jlz_325/blog/static/19174000920126893245653/</a></p>  
  156. <p><a href="http://www.linuxidc.com/Linux/2007-12/9680.htm">http://www.linuxidc.com/Linux/2007-12/9680.htm</a><br>  
  157. </p>  
  158. <p><a href="http://linux.chinaunix.net/techdoc/develop/2007/09/05/967137.shtml">http://linux.chinaunix.net/techdoc/develop/2007/09/05/967137.shtml</a><br>  
  159. </p>  
  160. <p><br>  
  161. </p>  
相關文章
相關標籤/搜索