ioctl函數
本函數影響由fd參數引用的一個打開的文件。
#include<unistd.h>
int ioctl( int fd, int request, .../* void *arg */ );
返回0:成功 -1:出錯
第三個參數總是一個指針,但指針的類型依賴於request參數。
我們可以把和網絡相關的請求劃分爲6類:
套接口操作
文件操作
接口操作
ARP高速緩存操作
路由表操作
流系統
下表列出了網絡相關ioctl請求的request參數以及arg地址必須指向的數據類型:
類別 |
Request |
說明 |
數據類型 |
套 接 口 |
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 |
|
|
套接口操作:
明確用於套接口操作的ioctl請求有三個,它們都要求ioctl的第三個參數是指向某個整數的一個指針。
SIOCATMARK: 如果本套接口的的度指針當前位於帶外標記,那就通過由第三個參數指向的整數返回一個非0值;否則返回一個0值。POSIX以函數sockatmark替換本請求。
SIOCGPGRP: 通過第三個參數指向的整數返回本套接口的進程ID或進程組ID,該ID指定針對本套接口的SIGIO或SIGURG信號的接收進程。本請求和fcntl的F_GETOWN命令等效,POSIX標準化的是fcntl函數。
SIOCSPGRP: 把本套接口的進程ID或者進程組ID設置成第三個參數指向的整數,該ID指定針對本套接口的SIGIO或SIGURG信號的接收進程,本請求和fcntl的F_SETOWN命令等效,POSIX標準化的是fcntl操作。
文件操作:
以下5個請求都要求ioctl的第三個參數指向一個整數。
FIONBIO: 根據ioctl的第三個參數指向一個0或非0值分別清除或設置本套接口的非阻塞標誌。本請求和O_NONBLOCK文件狀態標誌等效,而該標誌通過fcntl的F_SETFL命令清除或設置。
FIOASYNC: 根據iocl的第三個參數指向一個0值或非0值分別清除或設置針對本套接口的信號驅動異步I/O標誌,它決定是否收取針對本套接口的異步I/O信號(SIGIO)。本請求和O_ASYNC文件狀態標誌等效,而該標誌可以通過fcntl的F_SETFL命令清除或設置。
FIONREAD: 通過由ioctl的第三個參數指向的整數返回當前在本套接口接收緩衝區中的字節數。本特性同樣適用於文件,管道和終端。
FIOSETOWN: 對於套接口和SIOCSPGRP等效。
FIOGETOWN: 對於套接口和SIOCGPGRP等效。
接口配置:
得到系統中所有接口由SIOCGIFCONF請求完成,該請求使用ifconf結構,ifconf又使用ifreq
結構,如下所示:
Struct ifconf{
int ifc_len; // 緩衝區的大小
union{
caddr_t ifcu_buf; // input from user->kernel
struct ifreq *ifcu_req; // return of structures returned
}ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf //buffer address
#define ifc_req ifc_ifcu.ifcu_req //array of structures returned
#define IFNAMSIZ 16
struct ifreq{
char ifr_name[IFNAMSIZ]; // interface name, e.g., “le0”
union{
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
short ifru_flags;
int ifru_metric;
caddr_t ifru_data;
}ifr_ifru;
};
#define ifr_addr ifr_ifru.ifru_addr // address
#define ifr_dstaddr ifr_ifru.ifru_dstaddr // otner end of p-to-p link
#define ifr_broadaddr ifr_ifru.ifru_broadaddr // broadcast address
#define ifr_flags ifr_ifru.ifru_flags // flags
#define ifr_metric ifr_ifru.ifru_metric // metric
#define ifr_data ifr_ifru.ifru_data // for use by interface
再調用ioctl前我們必須先分撇一個緩衝區和一個ifconf結構,然後才初始化後者。如下圖
展示了一個ifconf結構的初始化結構,其中緩衝區的大小爲1024,ioctl的第三個參數指向
這樣一個ifconf結構。
ifc_len |
Ifc_buf |
1024
--------------------->緩存
假設內核返回2個ifreq結構,ioctl返回時通過同一個ifconf結構緩衝區填入了那2個ifreq結構,ifconf結構的ifc_len成員也被更新,以反映存放在緩衝區中的信息量。