本文将讨论 AIX Version 5.3 中提供的与网络操作和套接字相关的命令。在下列文件中列出了与套接字相关的命令和结构:
sys/ioctl.h
net/if_arp.h
net/if.h
net/netopt.h
netinet/in.h
应用程序开发人员可以使用这些命令,并且在 AIX Version 5.3 的文档中对这些命令进行了详细的描述。本文说明了有关 Internet Protocol Version 6 (IPv6) 地址和 Internet Protocol Version 4 (IPv4) 堆栈的常用命令的典型用法。
使用 ioctl 套接字控制选项
通常,网络程序需要了解系统中所有有关网络接口和 IP 地址的可用信息。现在,未来的应用程序可以支持 IPv4 和 IPv6 双协议栈。ioctl 结构需要对指针进行遍历和操作,以处理 IPv4 和 IPv6 地址在长度上的差别(除了使用合适的套接字结构 sockaddr_in6 或 sockaddr_storage 之外)。
AIX Version 5.3 提供了很多 ioctl 套接字控制选项,以提取各种有关网络接口的信息。这些 ioctl 命令用于查询接口的状态并对其属性进行操作。下面的部分中包含了一些有用的命令的代码段。有关 ioctl 命令的完整列表,请参见参考资料部分。
ioctl 命令所使用的结构
下面的清单介绍了一些最重要的结构,使用 ioctl 套接字命令时常常用到这些结构。
清单 1. struct ifreq (/usr/include/net/if.h)
struct ifreq {
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif
char ifr_name[IFNAMSIZ];
union {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
__ulong32_t ifru_flags;
int ifru_metric;
CADdr_t ifru_data;
u_short ifru_site6;
__ulong32_t ifru_mtu;
int ifru_baudrate;
} ifr_ifru;
Following Macros are provided for convenIEnce
#define ifr_addr ifr_ifru.ifru_addr
#define ifr_dstaddr ifr_ifru.ifru_dstaddr
#define ifr_broadaddr ifr_ifru.ifru_broadaddr
#define ifr_flags ifr_ifru.ifru_flags
#define ifr_metric ifr_ifru.ifru_metric
#define ifr_data ifr_ifru.ifru_data
#define ifr_site6 ifr_ifru.ifru_site6
#define ifr_mtu ifr_ifru.ifru_mtu
#define ifr_isno ifr_ifru.ifru_data
#define ifr_baudrate ifr_ifru.ifru_baudrate
};
清单 2. struct ifconf (/usr/include/net/if.h)
struct ifconf {
int ifc_len;
union {
caddr_t ifcu_buf;
struct ifreq *ifcu_req;
} ifc_ifcu;
Following macros are provided for convenience
#define ifc_buf ifc_ifcu.ifcu_buf
#define ifc_req ifc_ifcu.ifcu_req
};
代码示例
下面的表 1 介绍了一些接口检索命令。该信息来源于 IBM System p 和 AIX。
表 1. 接口检索命令
ioctl 命令描述
SIOCGSIZIFCONF 获得获取 SIOCGIFCONF 返回的所有接口的配置信息所需的内存。
ioctl(fd, SIOCGSIZIFCONF, (caddr_t)&ifconfsize);
int ifconfsize;
SIOCGIFADDR
SIOCSIFADDR
SIOCGIFADDR 获取接口地址,而 SIOCSIFADDR 设置接口地址。ifr.ifr_addr 字段返回地址。
ioctl(fd, SIOCGIFADDR, (caddr_t)&ifr, sizeof(struct ifreq));
ioctl(fd, SIOCSIFADDR, (caddr_t)&ifr, sizeof(struct ifreq));
struct ifreq ifr;
SIOCGIFCONF 返回系统中配置的所有接口的配置信息。
ioctl(fd, SIOCGIFCONF, (caddr_t)&ifc);
struct ifconf ifconf;
SIOCGSIZIFCONF
下面的代码段可以获取用来填充所有配置接口的信息所需的缓冲区大小。
清单 3. 使用 SIOCGSIZIFCONF 获得所需的缓冲区大小
int get_interface_size(int sd){
int ret,size;
ret=ioctl(sd,SIOCGSIZIFCONF,&size);
if(ret==-1){
perror("Error getting size of interface :");
return ret;
}
return size;
}
main
{
struct ifconf ifc;
int sd;
sd=socket(AF_INET6,SOCK_DGRAM,0);
printf("Size of memory needed = %d",get_interface_size(sd));
}
上面代码的输出是:
$> ./myprog
Size of memory needed = 628
SIOCGIFCONF 和 SIOCGIFADDR
SIOCGIFCONF 和 SIOCGIFADDR 命令可以用来检索接口的地址。SIOCGIFCONF 可以用来获取所有配置接口的信息,SIOCGIFADDR 可以用来检索特定接口的地址。
清单 4. 使用 SIOCGIFCONF 获取配置信息
int alloc_buffer_size(int sd,struct ifconf *ifc){
int ret=-1,bsz=sizeof(struct ifreq);
int prevsz=bsz;
ifc->ifc_req=NULL;
ifc->ifc_len=bsz;
do{
ifc->ifc_req=(struct ifreq *)realloc(ifc->ifc_req,bsz);
if(!ifc->ifc_req){
perror("Malloc failed :");
return ret;
}
ifc->ifc_len=bsz;
ret=ioctl(sd,SIOCGIFCONF,(caddr_t)ifc);
if(ret==-1){
perror("Error getting size of interface :");
return ret;
}
if(prevsz==ifc->ifc_len)
break;
else{
bsz*=2;
prevsz=(0==ifc->ifc_len ? bsz : ifc->ifc_len) ;
}
}while(1);
ifc->ifc_req=(struct ifreq *)realloc(ifc->ifc_req,prevsz);
return ifc->ifc_len;
}
在使用 ifreq 结构中的配置信息填充了列表之后,可以对其进行遍历以检索所需的数据。根据调用之后该结构中填充的套接字地址的长度,可以对这个指针进行移动。下面的清单 5 显示了上面代码的列表中获得的系统中可用的 IP。
清单 5. 从配置列表中检索信息
#define MAX(x,y) ((x) >(y) ? (x) : (y))
#define SIZE(p) MAX((p).sa_len, sizeof(p))
void print_ips(struct ifconf *ifc){
char *cp,*cplim,addr[INET6_ADDRSTRLEN];
struct ifreq *ifr=ifc->ifc_req;
cp=(char *)ifc->ifc_req;
cplim=cp+ifc->ifc_len;
for(;cpifr_name) + SIZE(ifr->ifr_addr))){
ifr=(struct ifreq *)cp;
printf("%s :",ifr->ifr_name);
getip(ifr,addr);
printf("%s",addr);
}
return ;
}
main
{
struct ifconf ifc;
int sd;
sd=socket(AF_INET6,SOCK_DGRAM,0);
alloc_buffer_size(sd,&ifc);
print_ips(&ifc);
}
上面代码的输出是:
$> ./myprog
en0 :6.3.6.0
en0 :9.182.192.169
en0 :fe80::209:6bff:feeb:70b2
sit0 :1.4.4.0
sit0 :::9.182.192.169
lo0 :24.3.0.0
lo0 :127.0.0.1
lo0 :::1
清单 6. 使用 SIOCGIFADDR 获取接口地址
void getip(struct ifreq *ifr,char *addr){
struct sockaddr *sa;
sa=(struct sockaddr *)&(ifr->ifr_addr);
switch(sa->sa_family){
case AF_INET6:
inet_ntop(AF_INET6,(struct in6_addr *)&(((struct sockaddr_in6 *)sa)->sin6_addr),
addr,INET6_ADDRSTRLEN);
break;
default : strcpy(addr,inet_ntoa(((struct sockaddr_in *)sa)->sin_addr));
}
return;
}
main
{
char netaddr[INET_ADDRSTRLEN];
int sd;
sd=socket(AF_INET,SOCK_DGRAM,0);
strcpy(ifr.ifr_name,"en0");
if((ioctl(sd,SIOCGIFADDR,(caddr_t)&ifr,sizeof(struct ifreq)))<0)
perror("Error : ");
getip(&ifr,netaddr);
printf("%s",netaddr);
}
上面代码的输出是:
$./myprog
9.182.192.35
下面的表 2 介绍了接口标志和一些属性检索命令。
表 2. 接口标志和属性检索命令
ioctl 命令描述
SIOCGIFFLAGS
SIOCSIFFLAGS
SIOCGIFFLAGS 可以获取接口标志。
SIOCSIFFLAGS 可以设置接口标志。
ioctl(fd, cmd, (caddr_t)&ifr);
struct ifreq ifr;
SIOCGIFFLAGS
在使用 SIOCGIFCONF 获取了接口列表之后,您可以使用 SIOCGIFFLAGS-SIOCSIFFLAGS 对来获取和设置接口的属性。接口标志表示为 IFF_XXX。有关完整的列表,请参阅文件 /usr/include/net/if.h。
下面的示例使用一对接口标志来检索其当前状态,并检查环回。也可以使用其他选项。
清单 7. 验证接口的状态和类型
for(;cp
ifr=(struct ifreq *)cp;
cp+=(sizeof(ifr->ifr_name) + SIZE(ifr->ifr_addr));
printf("%-9s ",ifr->ifr_name);
ret=ioctl(sd,SIOCGIFFLAGS,(caddr_t)ifr);
if(ret==-1){
perror("Error getting flags for interface :");
return ;
}
if((ifr->ifr_flags)&IFF_UP)
printf("UP");
else printf("DOWN");
if((ifr->ifr_flags)&IFF_LOOPBACK)
printf(",Loopback");
printf("");
}
上面代码的输出是:
$> ./myprog
en0 UP
en0 UP
en0 UP
sit0 UP
sit0 UP
lo0 UP,Loopback
lo0 UP,Loopback
lo0 UP,Loopback
清单 8. 设置接口标志
Partial output of ifconfig before setting the flag
sit0: flags=4900041
inet6 ::9.182.192.169/96
Code to set the interface flag
int set_interface_flag(int sd,short flag,char *interface){
struct ifreq ifr;
int oldflags;
strcpy(ifr.ifr_name,interface);
if((ioctl(sd,SIOCGIFFLAGS,(caddr_t)&ifr))==-1){
perror("Error getting interface flags :");
return -1;
}
printf("Setting new interface flag 0X%x",flag);
ifr.ifr_flags|=flag;
if((ioctl(sd,SIOCSIFFLAGS,(caddr_t)&ifr))==-1){
perror("Error setting interface flags :");
return -1;
}
return 0;
}
main
{
int sd;
sd=socket(AF_INET6,SOCK_DGRAM,0);
set_interface_flag(sd,IFF_NOTRAILERS,"sit0");
}
上面代码的输出是:
You must have permission to change the flag
$./myprog
Setting new interface flag 0X20
$ifconfig -a
.............
.............
sit0: flags=4900061
inet6 ::9.182.192.169/96
.............
.............
表 3 介绍了一些用于网络优化的命令。
表 3. 用于网络优化的命令
ioctl 命令描述
SIOCGIFMTU SIOCGIFMTU 可以获取接口的最大传输单元 (MTU)。
ioctl(fd, cmd, (caddr_t)&ifr);
struct ifreq ifr;
这个 MTU 值存储在 ifr.ifr_mtu 字段中。
SIOCGNETOPT
SIOCGNETOPT1
SIOCGNETOPT 可以获取一个网络选项的值。
ioctl(fd, cmd, (caddr_t)&oreq);
struct optreq oreq;
SIOCGNETOPT1 可以获取当前值、缺省值和网络选项的范围。
ioctl(fd, SIOCGNETOPT1, (caddr_t)&oreq);
struct optreq1 oreq;
SIOCGIFMTU
清单 9. 从 ifreq 结构获取 MTU
ret=ioctl(sd,SIOCGIFMTU,ifr);
if(ret==-1){
perror("Error getting mtu for interface :");
return ;
}
printf(" %d",ifr->ifr_mtu);
SIOCGNETOPT1
SIOCGNETOPT1 给出当前值、缺省值和网络选项的范围。
清单 10. 从 optreq1 结构获取网络选项
int print_network_options(int sd){
int ret;
struct optreq1 oreq;
oreq.getnext=1;
while((ioctl(sd,SIOCGNETOPT1,(caddr_t)&oreq))!=-1)
printf("%s = %s",oreq.name,oreq.data);
return 0;
}
上面代码的输出是:
$> ./myprog
arpqsize = 12
arpt_killc = 20
arptab_bsiz = 7
arptab_nb = 149
........
........
........
........
ifsize = 256
inet_stack_size = 16
ip6_defttl = 64
........
在 AIX 中,您还可以使用 no 命令来管理各种网络优化参数。有关更详细的信息,请参阅相应的 man 页面。
清单 11. AIX 计算机上“no”命令的输出
$> no -a|more
arpqsize = 12
arpt_killc = 20
arptab_bsiz = 7
arptab_nb = 149
bcastping = 0
clean_partial_conns = 0
delayack = 0
delayackports = {}
dgd_packets_lost = 3
dgd_ping_time = 5
dgd_retry_time = 5
directed_broadcast = 0
extendednetstats = 0
fasttimo = 200
........
........
总结
ioctl 命令的功能非常强大,您可以使用它们来访问或修改网络(或其他)设备的可配置参数。它们使用了各种各样的数据结构,应该使用正确的数据来填充这些数据结构,以便实现预期的结果。您将发现在使用 AF_INET 和 AF_INET6 系列时存在的区别。本文提供了一小部分常用命令子集的代码示例。要获得 AIX Version 5.3 中完整的命令清单,请转到参考资料部分。我们希望这些关于 ioctl 的信息对您有用。
转自:http://hi.baidu.com/leezongfanblog/blog/item/a86a564583934a88b3b7dc0e
最后补上一个用ioctl获取本机ip地址的例子
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <net/if.h>
#include <string.h>
#include <netdb.h>
#include <unistd.h>
int main()
{
//
//
}