ioctrl函數, socket函數

ioctrl函數, socket函數[1]
2010-03-02 18:09

ioctl函數java

本函數影響由fd 參數引用的一個打開的文件。linux

#include<unistd.h>ios

int ioctl( int fd, int request, .../* void *arg */ );編程

返回0 :成功    -1 :出錯緩存

第三個參數老是一個指針,但指針的類型依賴於request 參數。服務器

咱們能夠把和網絡相關的請求劃分爲6 類:網絡

套接口操做dom

文件操做異步

接口操做socket

ARP 高速緩存操做

路由表操做

流系統

下表列出了網絡相關ioctl 請求的request 參數以及arg 地址必須指向的數據類型:

類別/ Request/ 說明/ 數據類型

套接口

SIOCATMARK

是否位於帶外標記

int

SIOCSPGRP

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

int

SIOCGPGRP        

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

int

                

文件

FIOASYNC

設置/清除信號驅動異步I/O標誌

int

FIONREAD        

獲取接收緩存區中的字節數

int

FIOSETOWN        

設置文件的進程ID或進程組ID        

int

FIOGETOWN        

獲取文件的進程ID或進程組ID

int

FIONBIN        

設置/清除非阻塞I/O標誌

int

接口

SIOCGIFCONF        

獲取全部接口的清單

struct ifconf

SIOCSIFADDR        

設置接口地址        

struct ifreq

SIOCGIFADDR        

獲取接口地址        

struct ifreq

SIOCSIFFLAGS        

設置接口標誌        

struct ifreq

SIOCGIFFLAGS                

獲取接口標誌        

struct ifreq

SIOCSIFDSTADDR        

設置點到點地址

struct ifreq

SIOCGIFDSTADDR

獲取點到點地址

struct ifreq

SIOCGIFBRDADDR

獲取廣播地址        

struct ifreq

SIOCSIFBRDADDR

設置廣播地址        

struct ifreq

SIOCGIFNETMASK

獲取子網掩碼        

struct ifreq

SIOCSIFNETMASK

設置子網掩碼        

struct ifreq

SIOCGIFMETRIC

獲取接口的測度

struct ifreq

SIOCSIFMETRIC

設置接口的測度

struct ifreq

SIOCGIFMTU

獲取接口MTU

struct ifreq

SIOCxxx

還有不少取決於系統的實現


ARP

SIOCSARP

建立/修改ARP表項

struct arpreq

SIOCGARP

獲取ARP表項

struct arpreq

SIOCDARP

刪除ARP表項

struct arpreq

                

路由

SIOCADDRT

增長路徑        

struct rtentry

SIOCDELRT

刪除路徑        

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

結構,以下所示:

(略)

再調用ioctl 前咱們必須先分撇一個緩衝區和一個ifconf 結構,而後才初始化後者。以下圖

展現了一個ifconf 結構的初始化結構,其中緩衝區的大小爲1024 ,ioctl 的第三個參數指向

這樣一個ifconf 結構。

ifc_len         1024

Ifc_buf         ---------------------> 緩存

假設內核返回2 個ifreq 結構,ioctl 返回時經過同一個ifconf 結構緩衝區填入了那2 個ifreq 結構,

ifconf 結構的ifc_len 成員也被更新,以反映存放在緩衝區中的信息量

通常來說ioctl在用戶程序中的調用是:

ioctl(int fd,int command, (char*)argstruct)

ioctl調用與網絡編程有關(本文只討論這一點),文件描述符fd其實是由socket()系統調用返回的。

參數command的取值由/usr/include/linux/sockios.h 所規定。這些command的因爲功能的不一樣,可分爲如下幾個小類:

? 改變路由表 (例如 SIOCADDRT, SIOCDELRT),

? 讀/更新 ARP/RARP 緩存(如:SIOCDARP, SIOCSRARP),

? 通常的與網絡接口有關的(例如 SIOCGIFNAME, SIOCSIFADDR 等等)

在 Gooodies目錄下有不少樣例程序展現瞭如何使用ioctl。當你看這些程序時,注意參數argstruct是與參數command相關的。

例如,與路由表相關的ioctl使用rtentry這種結構,rtentry定義在/usr/include/linux/route.h(參見例子 adddefault.c)。

與ARP有關的ioctl調用使用arpreq結構,arpreq定義在/usr/include/linux /if_arp.h(參見例子arpread.c)

與網絡接口有關的ioctl調用使用的command參數一般看起來像SIOCxIFyyyy的形式,這裏x要麼是S(設定set,寫write),要麼是G(獲得get,讀read)。

在getifinfo.c程序中就使用了這種形式的command參數來讀 IP地址,硬件地址,廣播地址和獲得與網絡接口有關的一些標誌(flag)。

在這些ioctl調用中,第三個參數是ifreq結構,它在/usr /include/linux/if.h中定義。

在某些狀況下, ioctrl調用可能會使用到在sockios.h以外的新的定義,例如,WaveLAN無線網絡卡會保..........(還有不少內容,在此略過)

socket函數:

int socket(int domain,int type, int protocol);

domain:表示所使用的協議族;

type:表示套接口的類型;

protocol:表示所使用的協議族中某個特定的協議。

若是函數調用成功,套接口的描述符(非負整數)就做爲函數的返回值,假如返回值爲-1,就代表有錯誤發生。

利用socket函數來獲取網卡MAC信息時,domain參數取值AF_INET,表示採用internet協議族;type參數指定爲SOCK_DGRAM,表示採用數據報類型套接口,protocol參數在這種組合下只有惟一選擇,故用0填充。

I/O控制函數ioctl用於對文件進行底層控制,這裏的文件包含網卡、終端、磁帶機、套接口等軟硬件設施,實際的操做來自各個設備本身提供的ioctl接口。ioctl函數的原型以下:

int ioctl(int d,int request,…)

這裏,參數d取值套接口的描述符,第一個request參數指定經過socket傳輸的I/O類型。本實驗能夠取值 SIONGIFHWADDR(0x8927),表示取硬件地址。其餘取值及其含義詳見/usr/includr/linux/sockios.h。其後的 request參數用於爲實現I/O控制所必須傳入或傳出的參數。本實驗須要用ifr結構傳入網卡設備名,並傳出6B的MAC地址。

socket簡介:

所謂socket一般也稱做"套接字",用於描述IP地址和端口,是一個通訊鏈的句柄。應用程序一般經過"套接字"向網絡發出請求或者應答網絡請求

以J2SDK-1.3爲例,Socket和ServerSocket類庫位於java.net包中。ServerSocket用於服務器端,Socket是創建網絡鏈接時使用的。在鏈接成功時,應用程序兩端都會產生一個Socket實例,操做這個實例,完成所需的會話。對於一個網絡鏈接來講,套接字是平等的,並無差異,不由於在服務器端或在客戶端而產生不一樣級別。不論是Socket仍是ServerSocket它們的工做都是經過SocketImpl類及其子類完成的。

用ioctl得到本地ip地址時要用到兩個結構體ifconf和ifreq,它們對於大多數人
來講都是比較陌生的,這裏給你們一種比較簡單的理解方法,固然只一種幫助
理解的方法,在描述中可能會有一些地方與真實定義有所出入,僅供參考.

首先先認識一下ifconf和ifreq:

//ifconf一般是用來保存全部接口信息的


//if.h


struct

ifconf {    int


    ifc_len;            /* size of buffer    */


    union     {      char

*ifcu_buf;                        /* input from user->kernel*/


      struct

ifreq *ifcu_req;        /* return from kernel->user*/


    } ifc_ifcu;};#define


    ifc_buf    ifc_ifcu.ifcu_buf        /* buffer address    */


#define


    ifc_req    ifc_ifcu.ifcu_req        /* array of structures    */


//ifreq用來保存某個接口的信息


//if.h


struct
ifreq 
{   char
ifr_name[IFNAMSIZ];   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#define
ifr_dstaddr ifr_ifru.ifru_dstaddr#define
ifr_broadaddr ifr_ifru.ifru_broadaddr
上邊這兩個結構看起來比較複雜,咱們如今把它們簡單化一些:
好比說如今咱們向實現得到本地IP的功能。

咱們的作法是:
1. 先經過ioctl得到本地全部接口的信息,並保存在ifconf中
2. 再從ifconf中取出每個ifreq中表示ip地址的信息

具體使用時咱們能夠認爲ifconf就有兩個成員:
ifc_len 和 ifc_buf, 如圖一所示:

  

ifc_len:表示用來存放全部接口信息的緩衝區長度
ifc_buf:表示存放接口信息的緩衝區

因此咱們須要在程序開始時對ifconf的ifc_len和ifc_buf進行初始化 
接下來使用ioctl獲取全部接口信息,完成後ifc_len內存放實際得到的藉口信息總長度
而且信息被存放在ifc_buf中。 
以下圖示:(假設讀到兩個接口信息)

接下來咱們只須要從一個一個的接口信息獲取ip地址信息便可。

下面有一個簡單的參考:

#include #include #include #include #include in
.h>#include <string
.h>#include if
.h>#include int
main(){    int
i=0;    int
sockfd; struct
ifconf ifconf; unsigned char
buf[512]; struct
ifreq *ifreq;    //初始化ifconf


ifconf.ifc_len = 512; ifconf.ifc_buf = buf;      if
((sockfd = socket(AF_INET, SOCK_DGRAM, 0))<0)    {        perror("socket"
);        exit(1);    }    ioctl(sockfd, SIOCGIFCONF, &ifconf);    //獲取全部接口信息


    //接下來一個一個的獲取IP地址


ifreq = (struct
ifreq*)buf;    for
(i=(ifconf.ifc_len/sizeof
(struct
ifreq)); i>0; i--) {//      if(ifreq->ifr_flags == AF_INET){            //for ipv4


          printf("name = [%s]\n"
, ifreq->ifr_name);      printf("local addr = [%s]\n"
,inet_ntoa(((struct
sockaddr_in*)&(ifreq->ifr_addr))->sin_addr));      ifreq++;// }

}    return 0;}

相關文章
相關標籤/搜索