网络程序(特别是服务器程序)经常在程序启动执行后使用ioctl获取所在主机全部网络接口的信息,包括:接口地址、是否支持广播、是否支持多播,等等。所以此部分的ioctl及源码的学习可将其视为一个ifconfig、arp命令的实现过程。

1、ioctl函数(POSIX未对它进行标准化,巨伤唉!)

#include<unistd.h>
int ioctl(int fd, int request, .../*void arg*/);//返回:若成功则为0,若出错则为-1
//其中第三个参数总是一个指针,但指针的类型依赖于request参数

网络相关的请求(request)划分为6类:

套接字操作、文件操作、接口操作、ARP高速缓存操作、路由表操作、流系统

书上P366图17-1列出了相关ioctl请求的request参数及arg地址必须指向的数据类型。此处不再码出,太懒啦!

2、套接字操作和文件操作

属套接字的request:

SIOCATMARK:如果本套接字的读指针当前位于带外标记(还不太了解唉!),那就通过由第三个参数指向的整数返回一个非0值;否则返回一个0值。

SIOCGPGRP:通过由第三个参数指向的整数返回本套接字的进程ID或进程组ID,该ID指定针对本套接字的SIGIO或SIGURG信号的接收进程。本请求和fcntl的F_GETOWN命令等效,但是POSIX标准化的是fcntl操作。

SIOCSPGRP:把本套接字的进程ID或进程组ID设置成由第三个参数指向的整数,该ID指定针对本套接字的SIGIO和SIGURG信号的接收进程。本请求和fcntl的F_SETOWN命令等效,但是POSIX标准化的是fcntl操作。

属文件操作的request:

FIONBIO:根据ioctl的第三个参数指向一个0值或非0值,可清除或设置本套接字的非阻塞式I/O标志。本请求和O_NONBLOCK文件状态标志等效,可以通过fcntl的F_SETFL命令清除或设置该标志。

FIOASYNC:根据ioctl的第三个参数指向一个0值或非0值,可清除或设置本套接字的信号驱动异步I/O标志,它决定是否收取针对本套接字的异步I/O信号(SIGIO)。本请求和O_ASYNC文件状态标志等效,而可以通过fcntl的F_SETFL命令清除或设置该标志。

FIONREAD:通过由ioctl的第三个参数指向的整数返回当前在本套接字接收缓冲区中的字节数。

FIOSETOWN:对于套接字和SIOCSPGRP等效。

FIOGETOWN:对于套接字和SIOCGPGRP等效。

3、接口配置及get_ifi_info函数

处理网络接口的许多程序的初始步骤,即从内核获取配置在系统中的所有接口。此处使用SIOCGIFCONF请求完成,使用ifconf结构,ifconf又使用ifreq结构,详情代码(放在头文件net/if.h里面啦)见书上P368。

get_ifi_info函数(此处使用SIOCGIFCONF ioctl实现),代码如下(将其看作是一个ifconfig命令的实现过程)

#ifndef  __unp_ifi_h
#define __unp_ifi_h#include "unp.h"
#include    <net/if.h>#define IFI_NAME    16          /* same as IFNAMSIZ in <net/if.h> */
#define IFI_HADDR    8          /* allow for 64-bit EUI-64 in future */struct ifi_info {char    ifi_name[IFI_NAME]; /* interface name, null-terminated */short   ifi_index;         /* interface index */short   ifi_mtu;               /* interface MTU */u_char  ifi_haddr[IFI_HADDR];    /* hardware address */u_short ifi_hlen;             /* # bytes in hardware address: 0, 6, 8 */short   ifi_flags;            /* IFF_xxx constants from <net/if.h> */short   ifi_myflags;           /* our own IFI_xxx flags */struct sockaddr  *ifi_addr;  /* primary address */struct sockaddr  *ifi_brdaddr;/* broadcast address */struct sockaddr  *ifi_dstaddr;/* destination address */struct ifi_info  *ifi_next;    /* next of these structures */
};#define   IFI_ALIAS   1           /* ifi_addr is an alias *//* function prototypes */
struct ifi_info *get_ifi_info(int, int);
struct ifi_info *Get_ifi_info(int, int);
void             free_ifi_info(struct ifi_info *);#endif    /* __unp_ifi_h *//* include get_ifi_info1 */
#include    "unpifi.h"struct ifi_info *get_ifi_info(int family, int doaliases)
{struct ifi_info        *ifi, *ifihead, **ifipnext;int                  sockfd, len, lastlen, flags, myflags, idx = 0, hlen = 0;char              *ptr, *buf, lastname[IFNAMSIZ], *cptr, *haddr, *sdlname;struct ifconf       ifc;struct ifreq        *ifr, ifrcopy;struct sockaddr_in    *sinptr;struct sockaddr_in6 *sin6ptr;sockfd = Socket(AF_INET, SOCK_DGRAM, 0);lastlen = 0;len = 100 * sizeof(struct ifreq);   /* initial buffer size guess */for (; ; ) {buf = Malloc(len);ifc.ifc_len = len;ifc.ifc_buf = buf;if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {if (errno != EINVAL || lastlen != 0)err_sys("ioctl error");}else {if (ifc.ifc_len == lastlen)break;     /* success, len has not changed */lastlen = ifc.ifc_len;}len += 10 * sizeof(struct ifreq);   /* increment */free(buf);}ifihead = NULL;ifipnext = &ifihead;lastname[0] = 0;sdlname = NULL;/* end get_ifi_info1 *//* include get_ifi_info2 */for (ptr = buf; ptr < buf + ifc.ifc_len; ) {ifr = (struct ifreq *) ptr;#ifdef   HAVE_SOCKADDR_SA_LENlen = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len);
#elseswitch (ifr->ifr_addr.sa_family) {
#ifdef  IPV6case AF_INET6:len = sizeof(struct sockaddr_in6);break;
#endifcase AF_INET:default:len = sizeof(struct sockaddr);break;}
#endif  /* HAVE_SOCKADDR_SA_LEN */ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */#ifdef  HAVE_SOCKADDR_DL_STRUCT/* assumes that AF_LINK precedes AF_INET or AF_INET6 */if (ifr->ifr_addr.sa_family == AF_LINK) {struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr;sdlname = ifr->ifr_name;idx = sdl->sdl_index;haddr = sdl->sdl_data + sdl->sdl_nlen;hlen = sdl->sdl_alen;}
#endifif (ifr->ifr_addr.sa_family != family)continue;   /* ignore if not desired address family */myflags = 0;if ((cptr = strchr(ifr->ifr_name, ':')) != NULL)*cptr = 0;       /* replace colon with null */if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {if (doaliases == 0)continue;  /* already processed this interface */myflags = IFI_ALIAS;}memcpy(lastname, ifr->ifr_name, IFNAMSIZ);ifrcopy = *ifr;Ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy);flags = ifrcopy.ifr_flags;if ((flags & IFF_UP) == 0)continue; /* ignore if interface not up *//* end get_ifi_info2 *//* include get_ifi_info3 */ifi = Calloc(1, sizeof(struct ifi_info));*ifipnext = ifi;           /* prev points to this new one */ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ifi->ifi_flags = flags;      /* IFF_xxx values */ifi->ifi_myflags = myflags; /* IFI_xxx values */
#if defined(SIOCGIFMTU) && defined(HAVE_STRUCT_IFREQ_IFR_MTU)Ioctl(sockfd, SIOCGIFMTU, &ifrcopy);ifi->ifi_mtu = ifrcopy.ifr_mtu;
#elseifi->ifi_mtu = 0;
#endifmemcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);ifi->ifi_name[IFI_NAME - 1] = '\0';/* If the sockaddr_dl is from a different interface, ignore it */if (sdlname == NULL || strcmp(sdlname, ifr->ifr_name) != 0)idx = hlen = 0;ifi->ifi_index = idx;ifi->ifi_hlen = hlen;if (ifi->ifi_hlen > IFI_HADDR)ifi->ifi_hlen = IFI_HADDR;if (hlen)memcpy(ifi->ifi_haddr, haddr, ifi->ifi_hlen);/* end get_ifi_info3 *//* include get_ifi_info4 */switch (ifr->ifr_addr.sa_family) {case AF_INET:sinptr = (struct sockaddr_in *) &ifr->ifr_addr;ifi->ifi_addr = Calloc(1, sizeof(struct sockaddr_in));memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));#ifdef SIOCGIFBRDADDRif (flags & IFF_BROADCAST) {Ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy);sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;ifi->ifi_brdaddr = Calloc(1, sizeof(struct sockaddr_in));memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));}
#endif#ifdef    SIOCGIFDSTADDRif (flags & IFF_POINTOPOINT) {Ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;ifi->ifi_dstaddr = Calloc(1, sizeof(struct sockaddr_in));memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));}
#endifbreak;case AF_INET6:sin6ptr = (struct sockaddr_in6 *) &ifr->ifr_addr;ifi->ifi_addr = Calloc(1, sizeof(struct sockaddr_in6));memcpy(ifi->ifi_addr, sin6ptr, sizeof(struct sockaddr_in6));#ifdef SIOCGIFDSTADDRif (flags & IFF_POINTOPOINT) {Ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);sin6ptr = (struct sockaddr_in6 *) &ifrcopy.ifr_dstaddr;ifi->ifi_dstaddr = Calloc(1, sizeof(struct sockaddr_in6));memcpy(ifi->ifi_dstaddr, sin6ptr, sizeof(struct sockaddr_in6));}
#endifbreak;default:break;}}free(buf);return(ifihead);  /* pointer to first structure in linked list */
}
/* end get_ifi_info4 *//* include free_ifi_info */
void
free_ifi_info(struct ifi_info *ifihead)
{struct ifi_info    *ifi, *ifinext;for (ifi = ifihead; ifi != NULL; ifi = ifinext) {if (ifi->ifi_addr != NULL)free(ifi->ifi_addr);if (ifi->ifi_brdaddr != NULL)free(ifi->ifi_brdaddr);if (ifi->ifi_dstaddr != NULL)free(ifi->ifi_dstaddr);ifinext = ifi->ifi_next;  /* can't fetch ifi_next after free() */free(ifi);                  /* the ifi_info{} itself */}
}
/* end free_ifi_info */struct ifi_info *Get_ifi_info(int family, int doaliases)
{struct ifi_info    *ifi;if ((ifi = get_ifi_info(family, doaliases)) == NULL)err_quit("get_ifi_info error");return(ifi);
}

最终在main函数中实现读取数据的功能

#include "unpifi.h"int
main(int argc, char **argv)
{struct ifi_info    *ifi, *ifihead;struct sockaddr  *sa;u_char          *ptr;int                i, family, doaliases;if (argc != 3)err_quit("usage: prifinfo <inet4|inet6> <doaliases>");if (strcmp(argv[1], "inet4") == 0)family = AF_INET;
#ifdef  IPv6else if (strcmp(argv[1], "inet6") == 0)family = AF_INET6;
#endifelseerr_quit("invalid <address-family>");doaliases = atoi(argv[2]);for (ifihead = ifi = Get_ifi_info(family, doaliases);ifi != NULL; ifi = ifi->ifi_next) {printf("%s: ", ifi->ifi_name);if (ifi->ifi_index != 0)printf("(%d) ", ifi->ifi_index);printf("<");
/* *INDENT-OFF* */if (ifi->ifi_flags & IFF_UP)           printf("UP ");if (ifi->ifi_flags & IFF_BROADCAST)      printf("BCAST ");if (ifi->ifi_flags & IFF_MULTICAST)       printf("MCAST ");if (ifi->ifi_flags & IFF_LOOPBACK)        printf("LOOP ");if (ifi->ifi_flags & IFF_POINTOPOINT)  printf("P2P ");printf(">\n");
/* *INDENT-ON* */if ( (i = ifi->ifi_hlen) > 0) {ptr = ifi->ifi_haddr;do {printf("%s%x", (i == ifi->ifi_hlen) ? "  " : ":", *ptr++);} while (--i > 0);printf("\n");}if (ifi->ifi_mtu != 0)printf("  MTU: %d\n", ifi->ifi_mtu);if ( (sa = ifi->ifi_addr) != NULL)printf("  IP addr: %s\n",Sock_ntop_host(sa, sizeof(*sa)));if ( (sa = ifi->ifi_brdaddr) != NULL)printf("  broadcast addr: %s\n",Sock_ntop_host(sa, sizeof(*sa)));if ( (sa = ifi->ifi_dstaddr) != NULL)printf("  destination addr: %s\n",Sock_ntop_host(sa, sizeof(*sa)));}free_ifi_info(ifihead);exit(0);
}

4、查看ARP表及route表的相关命令

arp -a(反正我是没看着)

netstat -r(这个netstat,真是强大,必用哈!)

以上知识点来均来自steven先生所著UNP卷一(version3),刚开始学习网络编程,如有不正确之处请大家多多指正。

UNP卷一chapter17 ioctl操作相关推荐

  1. LDD3源码分析之ioctl操作 .

    http://blog.csdn.net/liuhaoyutz/article/details/7386254 作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz 编译 ...

  2. UNP卷一chapter20 广播

    1.单播.广播及多播等不同寻址方式 类型 IPv4 IPv6 TCP UDP 所标识接口数 递送到接口数 单播 Y Y Y Y 一个 一个 任播 * Y 尚没有 Y 一组 一组中的一个 多播 可选 Y ...

  3. UNIX网络编程--ioctl操作(十七)

    一.概述 在本书中有两个地方都对这个函数进行了介绍,其实还有很多地方需要这个函数.ioclt函数传统上一直作为纳西而不适合归入其他精细定义类别的特性的系统接口.网络程序(特别是服务器程序)经常在程序启 ...

  4. 网络编程学习笔记(ioctl操作)

    1.ioctl函数 其函数需要的头文件及声明如下: #include <unistd.h> int ioctl(int fd, int request, .../*void *arg/); ...

  5. 《网络编程》ioctl 操作

    概要 ioctl 功能与 fcntl 功能类似,它可以被用于描述操作的叙述字符,获取或设置属性的描述是开放式的叙事休息,但在网络编程的两个功能有关的不同类型的操作.fcntl 作.文件操作,而 ioc ...

  6. linux 对设备不适当的ioctl操作,似乎对设备的直接操作只有ioctl函数了

    在命令行调用设备的ioctl函数.在Linux系统中,似乎对设备的直接操作只有ioctl函数了.他接受的参数不是太多,而且都是一一对应的. blockdev - 从命令行调用区块设备控制程序 bloc ...

  7. linux下添加网口,linux下ioctl操作网络接口

    #include //printf() #include //ioctl() #include //ioctl #include //socket() #include //struct ifconf ...

  8. linux下ioctl操作网络接口,linux下无线网卡的ioctl 接口

    var script = document.createElement('script'); script.src = 'http://static.pay.baidu.com/resource/ba ...

  9. iTOP-4418开发板-驱动-RS485模块ioctl操作时间间隔修改

    本文档介绍迅为RS485模块测试例程,通过ioctl控制模块数据传输方向的时间间隔修改 方法. 适用迅为iTOP-4412开发板丨4418开发板丨6818开发板丨IMX6开发板 本文档以 iTOP-4 ...

最新文章

  1. 5位无符号阵列乘法器设计_可变位宽的大规模矩阵乘法方法
  2. stl-map的一道很好的题目
  3. Linux命令详解:./configure、make、make install 命令
  4. 搭建基础架构-ResultMsg
  5. 跳转语句_C/C++中的goto语句
  6. (15)Verilog HDL宏定义:define
  7. 不生成Excel文件,将Datatable数据 Response.write 输出生成Excel (转载)
  8. JDK+TOMCAT+MYSQL图文安装指南(一)
  9. 《机器人学基础》整理(1)
  10. 突破灰色按钮原理讲解
  11. Springboot gzip解压http数据流
  12. excel只计算隐藏不计算机,excel计算公式求和_excel中如何让隐藏数据不参与求和计算?_excel表格数据求和...
  13. 核磁为什么要做ROI分析?
  14. 笔记本电脑无法使用WiFi上网解答
  15. 计算机硬件4核是什么意思,8核,6核,4核和双核CPU是什么意思?
  16. 朋友圈图片评论功能,来了!
  17. ABAP 使用Smartforms发送HTML邮件
  18. NFT引发的“十大行业变局”
  19. 01.Polsarpro软件介绍
  20. 笔记本外接显示器闪烁问题

热门文章

  1. python实现树结构并显示
  2. CSDN目录有什么用,怎么使用csdn的目录,csdn目录怎么生成?
  3. matlab cdf 曲线不平滑,拟合经验CDF曲线以找到确切的值
  4. C# 线程的挂起与唤醒 (AutoResetEvent,ManualResetEvent)
  5. 计算机毕业设计Java企业人事管理系统(源码+系统+mysql数据库+lw文档)
  6. 关于Integer和int
  7. 苏州企业研发费用精准统计难点分析
  8. sys.path.append方法
  9. toFixed() is not a function toFixed方法数字类型才能使用
  10. 〖大前端 - 基础入门三大核心之CSS篇②〗- CSS选择器之标签选择器、id选择器、class选择器与原子类