UNP学习笔记(第十七章 ioctl操作)

ioctl相当于一个杂物箱,它一直作为那些不适合归入其他精细定义类别的特性的系统接口。

本章笔记先放着,到时候有需要再看

ioctl函数

#include <unistd.h>
int ioctl(int fd,int request,.../* void *arg */);

其中第三个参数总是一个指针,但指针的类型依赖于request参数。

我们可以把网络相关的请求(request)划分为6类:

1.套接字操作

2.文件操作

3.接口操作

4.ARP高速缓存操作

5.路由表操作

6.流系统

下图列出了网络相关ioctl请求的request参数以及arg地址必须指向的数据类型:

套接字操作

SIOCATMARK    如果本套接字的读指针当前位于带外标记,那就通过由第三个参数指向的整数返回一个非0值,否则返回一个0值

SIOCGPGRP       通过由第三个参数指向的整数返回本套接字的进程ID或进程组ID

SIOCSGRP         把本进程进程ID或进程组ID设置成由第三个参数指向的整数

文件操作

FIONBIO       根据ioctl的第三个参数指向一个0值或非0值,可清除或设置本套接字的非阻塞式I/O标志

FIOASYNC     根据ioctl的第三个参数指向一个0值或非0值,可清除或设置本套接字的信号驱动异步I/O标志,它决定是否收取针对本套接字的异步I/O信号(SIGIO)

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

FIOSETOWN   对于套接字和SIOCSPGRP等效

FIOGETOWN   对于套接字和SIOCGPGRP等效

接口配置

需处理网络接口的许多程序的初始步骤之一就是从内核获取配置在系统中的所有接口。本任务由SIOCGIFCONF请求完成,它使用ifconf结构,ifconf又使用ifreq结构。这两个结构定义如下:

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

在调用ioctl前我们先分配一个缓冲区和一个ifconf结构,然后初始化后者。下面展示这个ifconf结构的初始化结果,其中缓冲区的大小为1024字节

假设内核返回2个ifreq结构,在ioctl返回时通过同一个ifconf结构所返回的值如下图。缓冲区被填入两个ifreq结构,而且ifconf结构的ifc_len成员也被更新

get_ifi_info函数(暂时不看)

我们使用ioctl开发一个名为get_ifi_info的函数,它返回一个结构链表,其中每个结构对应一个当前处于“up”状态的接口。

头文件

 1 /* Our own header for the programs that need interface configuration info.
 2    Include this file, instead of "unp.h". */
 3
 4 #ifndef    __unp_ifi_h
 5 #define    __unp_ifi_h
 6
 7 #include    "unp.h"
 8 #include    <net/if.h>
 9
10 #define    IFI_NAME    16            /* same as IFNAMSIZ in <net/if.h> */
11 #define    IFI_HADDR     8            /* allow for 64-bit EUI-64 in future */
12
13 struct ifi_info {
14   char    ifi_name[IFI_NAME];    /* interface name, null-terminated */
15   short   ifi_index;            /* interface index */
16   short   ifi_mtu;                /* interface MTU */
17   u_char  ifi_haddr[IFI_HADDR];    /* hardware address */
18   u_short ifi_hlen;                /* # bytes in hardware address: 0, 6, 8 */
19   short   ifi_flags;            /* IFF_xxx constants from <net/if.h> */
20   short   ifi_myflags;            /* our own IFI_xxx flags */
21   struct sockaddr  *ifi_addr;    /* primary address */
22   struct sockaddr  *ifi_brdaddr;/* broadcast address */
23   struct sockaddr  *ifi_dstaddr;/* destination address */
24   struct ifi_info  *ifi_next;    /* next of these structures */
25 };
26
27 #define    IFI_ALIAS    1            /* ifi_addr is an alias */
28
29                     /* function prototypes */
30 struct ifi_info    *get_ifi_info(int, int);
31 struct ifi_info    *Get_ifi_info(int, int);
32 void             free_ifi_info(struct ifi_info *);
33
34 #endif    /* __unp_ifi_h */

main函数

 1 #include    "unpifi.h"
 2
 3 int
 4 main(int argc, char **argv)
 5 {
 6     struct ifi_info    *ifi, *ifihead;
 7     struct sockaddr    *sa;
 8     u_char            *ptr;
 9     int                i, family, doaliases;
10
11     if (argc != 3)
12         err_quit("usage: prifinfo <inet4|inet6> <doaliases>");
13
14     if (strcmp(argv[1], "inet4") == 0)
15         family = AF_INET;
16 #ifdef    IPv6
17     else if (strcmp(argv[1], "inet6") == 0)
18         family = AF_INET6;
19 #endif
20     else
21         err_quit("invalid <address-family>");
22     doaliases = atoi(argv[2]);
23
24     for (ifihead = ifi = Get_ifi_info(family, doaliases);
25          ifi != NULL; ifi = ifi->ifi_next) {
26         printf("%s: ", ifi->ifi_name);
27         if (ifi->ifi_index != 0)
28             printf("(%d) ", ifi->ifi_index);
29         printf("<");
30 /* *INDENT-OFF* */
31         if (ifi->ifi_flags & IFF_UP)            printf("UP ");
32         if (ifi->ifi_flags & IFF_BROADCAST)        printf("BCAST ");
33         if (ifi->ifi_flags & IFF_MULTICAST)        printf("MCAST ");
34         if (ifi->ifi_flags & IFF_LOOPBACK)        printf("LOOP ");
35         if (ifi->ifi_flags & IFF_POINTOPOINT)    printf("P2P ");
36         printf(">\n");
37 /* *INDENT-ON* */
38
39         if ( (i = ifi->ifi_hlen) > 0) {
40             ptr = ifi->ifi_haddr;
41             do {
42                 printf("%s%x", (i == ifi->ifi_hlen) ? "  " : ":", *ptr++);
43             } while (--i > 0);
44             printf("\n");
45         }
46         if (ifi->ifi_mtu != 0)
47             printf("  MTU: %d\n", ifi->ifi_mtu);
48
49         if ( (sa = ifi->ifi_addr) != NULL)
50             printf("  IP addr: %s\n",
51                         Sock_ntop_host(sa, sizeof(*sa)));
52         if ( (sa = ifi->ifi_brdaddr) != NULL)
53             printf("  broadcast addr: %s\n",
54                         Sock_ntop_host(sa, sizeof(*sa)));
55         if ( (sa = ifi->ifi_dstaddr) != NULL)
56             printf("  destination addr: %s\n",
57                         Sock_ntop_host(sa, sizeof(*sa)));
58     }
59     free_ifi_info(ifihead);
60     exit(0);
61 }

get_ifi_info.c

  1 /* include get_ifi_info1 */
  2 #include    "unpifi.h"
  3
  4 struct ifi_info *
  5 get_ifi_info(int family, int doaliases)
  6 {
  7     struct ifi_info        *ifi, *ifihead, **ifipnext;
  8     int                    sockfd, len, lastlen, flags, myflags, idx = 0, hlen = 0;
  9     char                *ptr, *buf, lastname[IFNAMSIZ], *cptr, *haddr, *sdlname;
 10     struct ifconf        ifc;
 11     struct ifreq        *ifr, ifrcopy;
 12     struct sockaddr_in    *sinptr;
 13     struct sockaddr_in6    *sin6ptr;
 14
 15     sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
 16
 17     lastlen = 0;
 18     len = 100 * sizeof(struct ifreq);    /* initial buffer size guess */
 19     for ( ; ; ) {
 20         buf = Malloc(len);
 21         ifc.ifc_len = len;
 22         ifc.ifc_buf = buf;
 23         if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
 24             if (errno != EINVAL || lastlen != 0)
 25                 err_sys("ioctl error");
 26         } else {
 27             if (ifc.ifc_len == lastlen)
 28                 break;        /* success, len has not changed */
 29             lastlen = ifc.ifc_len;
 30         }
 31         len += 10 * sizeof(struct ifreq);    /* increment */
 32         free(buf);
 33     }
 34     ifihead = NULL;
 35     ifipnext = &ifihead;
 36     lastname[0] = 0;
 37     sdlname = NULL;
 38 /* end get_ifi_info1 */
 39
 40 /* include get_ifi_info2 */
 41     for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
 42         ifr = (struct ifreq *) ptr;
 43
 44 #ifdef    HAVE_SOCKADDR_SA_LEN
 45         len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len);
 46 #else
 47         switch (ifr->ifr_addr.sa_family) {
 48 #ifdef    IPV6
 49         case AF_INET6:
 50             len = sizeof(struct sockaddr_in6);
 51             break;
 52 #endif
 53         case AF_INET:
 54         default:
 55             len = sizeof(struct sockaddr);
 56             break;
 57         }
 58 #endif    /* HAVE_SOCKADDR_SA_LEN */
 59         ptr += sizeof(ifr->ifr_name) + len;    /* for next one in buffer */
 60
 61 #ifdef    HAVE_SOCKADDR_DL_STRUCT
 62         /* assumes that AF_LINK precedes AF_INET or AF_INET6 */
 63         if (ifr->ifr_addr.sa_family == AF_LINK) {
 64             struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr;
 65             sdlname = ifr->ifr_name;
 66             idx = sdl->sdl_index;
 67             haddr = sdl->sdl_data + sdl->sdl_nlen;
 68             hlen = sdl->sdl_alen;
 69         }
 70 #endif
 71
 72         if (ifr->ifr_addr.sa_family != family)
 73             continue;    /* ignore if not desired address family */
 74
 75         myflags = 0;
 76         if ( (cptr = strchr(ifr->ifr_name, ‘:‘)) != NULL)
 77             *cptr = 0;        /* replace colon with null */
 78         if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
 79             if (doaliases == 0)
 80                 continue;    /* already processed this interface */
 81             myflags = IFI_ALIAS;
 82         }
 83         memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
 84
 85         ifrcopy = *ifr;
 86         Ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy);
 87         flags = ifrcopy.ifr_flags;
 88         if ((flags & IFF_UP) == 0)
 89             continue;    /* ignore if interface not up */
 90 /* end get_ifi_info2 */
 91
 92 /* include get_ifi_info3 */
 93         ifi = Calloc(1, sizeof(struct ifi_info));
 94         *ifipnext = ifi;            /* prev points to this new one */
 95         ifipnext = &ifi->ifi_next;    /* pointer to next one goes here */
 96
 97         ifi->ifi_flags = flags;        /* IFF_xxx values */
 98         ifi->ifi_myflags = myflags;    /* IFI_xxx values */
 99 #if defined(SIOCGIFMTU) && defined(HAVE_STRUCT_IFREQ_IFR_MTU)
100         Ioctl(sockfd, SIOCGIFMTU, &ifrcopy);
101         ifi->ifi_mtu = ifrcopy.ifr_mtu;
102 #else
103         ifi->ifi_mtu = 0;
104 #endif
105         memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
106         ifi->ifi_name[IFI_NAME-1] = ‘\0‘;
107         /* If the sockaddr_dl is from a different interface, ignore it */
108         if (sdlname == NULL || strcmp(sdlname, ifr->ifr_name) != 0)
109             idx = hlen = 0;
110         ifi->ifi_index = idx;
111         ifi->ifi_hlen = hlen;
112         if (ifi->ifi_hlen > IFI_HADDR)
113             ifi->ifi_hlen = IFI_HADDR;
114         if (hlen)
115             memcpy(ifi->ifi_haddr, haddr, ifi->ifi_hlen);
116 /* end get_ifi_info3 */
117 /* include get_ifi_info4 */
118         switch (ifr->ifr_addr.sa_family) {
119         case AF_INET:
120             sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
121             ifi->ifi_addr = Calloc(1, sizeof(struct sockaddr_in));
122             memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
123
124 #ifdef    SIOCGIFBRDADDR
125             if (flags & IFF_BROADCAST) {
126                 Ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy);
127                 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
128                 ifi->ifi_brdaddr = Calloc(1, sizeof(struct sockaddr_in));
129                 memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
130             }
131 #endif
132
133 #ifdef    SIOCGIFDSTADDR
134             if (flags & IFF_POINTOPOINT) {
135                 Ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);
136                 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
137                 ifi->ifi_dstaddr = Calloc(1, sizeof(struct sockaddr_in));
138                 memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
139             }
140 #endif
141             break;
142
143         case AF_INET6:
144             sin6ptr = (struct sockaddr_in6 *) &ifr->ifr_addr;
145             ifi->ifi_addr = Calloc(1, sizeof(struct sockaddr_in6));
146             memcpy(ifi->ifi_addr, sin6ptr, sizeof(struct sockaddr_in6));
147
148 #ifdef    SIOCGIFDSTADDR
149             if (flags & IFF_POINTOPOINT) {
150                 Ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);
151                 sin6ptr = (struct sockaddr_in6 *) &ifrcopy.ifr_dstaddr;
152                 ifi->ifi_dstaddr = Calloc(1, sizeof(struct sockaddr_in6));
153                 memcpy(ifi->ifi_dstaddr, sin6ptr, sizeof(struct sockaddr_in6));
154             }
155 #endif
156             break;
157
158         default:
159             break;
160         }
161     }
162     free(buf);
163     return(ifihead);    /* pointer to first structure in linked list */
164 }
165 /* end get_ifi_info4 */
166
167 /* include free_ifi_info */
168 void
169 free_ifi_info(struct ifi_info *ifihead)
170 {
171     struct ifi_info    *ifi, *ifinext;
172
173     for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
174         if (ifi->ifi_addr != NULL)
175             free(ifi->ifi_addr);
176         if (ifi->ifi_brdaddr != NULL)
177             free(ifi->ifi_brdaddr);
178         if (ifi->ifi_dstaddr != NULL)
179             free(ifi->ifi_dstaddr);
180         ifinext = ifi->ifi_next;    /* can‘t fetch ifi_next after free() */
181         free(ifi);                    /* the ifi_info{} itself */
182     }
183 }
184 /* end free_ifi_info */
185
186 struct ifi_info *
187 Get_ifi_info(int family, int doaliases)
188 {
189     struct ifi_info    *ifi;
190
191     if ( (ifi = get_ifi_info(family, doaliases)) == NULL)
192         err_quit("get_ifi_info error");
193     return(ifi);
194 }

运行情况

接口操作

SIOCGIFCONF请求为每个已配置的接口返回其明知以及一个套接字地址结构。我们接着可以发出多个接口类的其他请求以设置或获取每个接口的其他特性

这些请求的get版本(SIOCGxxx)通常由netstat程序发出,set版本(SIOCSxxx)通常由ifconfig程序发出

这些请求接受或返回一个ifreq结构中的信息,而这个结构的地址作为ioctl调用的第三个参数。

SIGCGIFADDR   在ifr_addr成员中返回单播地址

SIOCSIFADDR    用ifr_addr成员设置接口地址

SIOCGIFFLAGS   在ifr_flags成员中返回接口标志,如:是否处于在工状态(IFF_UP)

SIOCSIFFLAGS    用ifr_flags成员设置接口标志

SIOCGIFDSTADDR  在if_dstaddr成员中返回点到点地址

SIGCSIFDSTADDR  用if_dstaddr成员设置点到点地址

SIOCGIFBRDADDR  在ifr_broadaddr成员中返回广播地址

SIOCSIFBRDADDR   用ifr_broadaddr成员设置广播地址

SIOCGIFNETMASK    在ifr_addr成员中返回子网掩码

SIOCSIFNETMASK    用ifr_addr成员设置子网掩码

SIOCGIFMETRIC   在ifr_metric成员返回接口测度

SIGCSIFMETRIC   用ifr_metric成员设置接口测度

ARP高速缓存操作

这些请求使用如下所示的arpreq结构

struct arpreq{
  struct sockaddr arp_pa; //协议地址
  struct sockaddr arp_ha; //硬件地址
  int arp_flags;//标志位
}

#define ATR_INUSE  0x01   /* entry in use */
#define ATF_COM    0x02   /* completed entry (hardware addr valid) */
#define ATF_PERM   0x04 /* permanent entry */
#define ATF_PUBL   0x08 /* published entry (repond for other host) */

操纵ARP高速缓存的ioctl请求有以下3个

SIOCSARP    把一个新的表项加到ARP高速缓存,或者修改其中一个已经存在的表项

SIOCDARP    从ARP高速缓存中删除一个表项。调用者指定要删除的arp_pa

SIOCGARP    从ARP高速缓存中获取一个表项。调用者指定arp_pa,相应的硬件地址随标志一起返回

下面程序用于输出主机的硬件地址

 1 #include    "unpifi.h"
 2 #include    <net/if_arp.h>
 3
 4 int
 5 main(int argc, char **argv)
 6 {
 7     int                    sockfd;
 8     struct ifi_info            *ifi;
 9     unsigned char        *ptr;
10     struct arpreq        arpreq;
11     struct sockaddr_in    *sin;
12
13     sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
14     for (ifi = get_ifi_info(AF_INET, 0); ifi != NULL; ifi = ifi->ifi_next) {
15         printf("%s: ", Sock_ntop(ifi->ifi_addr, sizeof(struct sockaddr_in)));
16
17         sin = (struct sockaddr_in *) &arpreq.arp_pa;
18         memcpy(sin, ifi->ifi_addr, sizeof(struct sockaddr_in));
19
20         if (ioctl(sockfd, SIOCGARP, &arpreq) < 0) {
21             err_ret("ioctl SIOCGARP");
22             continue;
23         }
24
25         ptr = &arpreq.arp_ha.sa_data[0];
26         printf("%x:%x:%x:%x:%x:%x\n", *ptr, *(ptr+1),
27                *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5));
28     }
29     exit(0);
30 }

先调用get_ifi_info获取本机所有的IP地址,然后在一个循环中遍历每个地址

使用inet_ntop显示IP地址

使用ioctl调用返回硬件地址(SIOCGARP)

路由表操作

有些系统提供两个用于操纵路由表的ioctl请求,在支持路由域套接字的系统中,这些请求改由路由套接字完成

SIOCADDRT   往路由表中增加一个表项

SIOCDELRT    从路由表中删除一个表项

时间: 2024-11-10 00:52:19

UNP学习笔记(第十七章 ioctl操作)的相关文章

UNP学习笔记(第二章:传输层)

本章的焦点是传输层,包括TCP.UDP和SCTP. 绝大多数客户/服务器网络应用使用TCP或UDP.SCTP是一个较新的协议. UDP是一个简单的.不可靠的数据报协议.而TCP是一个复杂.可靠的字节流协议. 这里重点放在TCP中. 用户数据报协议(UNP) 应用程序往UDP套接字写入一个消息,该消息随后被封装到一个UDP数据报,该UDP数据报进而又被封装到一个IP数据报,然后发送到目的地(面向非连接的). UDP不保证UDP数据报会达到最终目的地,不保证各个数据报的先后顺序跨网路后保持不变,也不

UNP学习笔记(第一章 简介)

环境搭建 1.下载解压unpv13e.tar.gz 2.进入目录执行 ./configurecd lib //进入lib目录make //执行make命令 3.将生成的libunp.a静态库复制到/usr/lib/和/usr/lib64/中 cd .. //返回unpv13e目录sudo cp libunp.a /usr/lib sudo cp libunp.a /usr/lib64 4.修改unp.h并将其和config.h拷贝到/usr/include中,为了以后include方便 vi l

iOS学习笔记(十七)——文件操作(NSFileManager)

http://blog.csdn.net/xyz_lmn/article/details/8968213 iOS的沙盒机制,应用只能访问自己应用目录下的文件.ios不像Android,没有SD卡概念,不能直接访问图像.视频等内容.iOS应用产生的内容,如图像.文件.缓存内容等都必须存储在自己的沙盒内.默认情况下,每个沙盒含有3个文件夹:Documents, Library 和 tmp.Library包含Caches.Preferences目录.               上面的完整路径为:用户

【算法导论】学习笔记——第6章 堆排序

堆这个数据结构应用非常广泛,数字图像处理的算法里也见过.似乎记得以前老师上课说需要用树结构实现堆排序,看了一下算法导论才明白其精髓.堆虽然是一棵树,但显然没必要非得用树结构实现堆排序.堆排序的性质很好,算法时间复杂度为O(nlgn). 1. 堆排序的简要说明.二叉堆可以分为两种形式:最大堆和最小堆.在最大堆中,最大堆性质是指除了根以外的所有结点i都要满足: A[PARENT(i)] >= A[i]:在最小堆中,最小堆性质是指除了根以外的所有结点i都要满足: A[PARENT(i)] <= A[

java JDK8 学习笔记——第16章 整合数据库

第十六章 整合数据库 16.1 JDBC入门 16.1.1 JDBC简介 1.JDBC是java联机数据库的标准规范.它定义了一组标准类与接口,标准API中的接口会有数据库厂商操作,称为JDBC驱动程序. 2.JDBC标准主要分为两个部分:JDBC应用程序开发者接口和JDBC驱动程序开发者接口.应用程序需要联机数据库,其相关API主要在java.sql和javax.sql两个包中. 3.应用程序使用JDBC联机数据库的通用语法: Connection conn = DriverManager.g

APUE学习笔记:第九章 进程关系

9.1 引言 本章将更详尽地说明进程组以及POSIX.1引入的会话的概念.还将介绍登陆shell(登录时所调用的)和所有从登陆shell启动的进程之间的关系. 9.1 终端登陆 系统管理员创建通常名为/etc/ttys的文件,其中每个终端设备都有一行,每一行说明设备名传递给getty程序的参数.当系统自举时,内核创建进程ID为1的进程,依旧是init进程.init进程使系统进入多用户状态.init进程读文件/etc/ttys,对每一个允许登陆的终端设备,init调用一次fork,所生成的子进程则

APUE学习笔记:第一章 UNUX基础知识

1.2 UNIX体系结构 从严格意义上,可将操作系统定义为一种软件(内核),它控制计算机硬件资源,提供程序运行环境.内核的接口被称为系统调用.公用函数库构建在系统调用接口之上,应用软件即可使用公用函数库,也可使用系统调用.shell是一种特殊的应用程序,它为运行其他应用程序提供了一个接口 从广义上,操作系统包括了内核和一些其他软件,这些软件使得计算机能够发挥作用,并给予计算机以独有的特性(软件包括系统实用程序,应用软件,shell以及公用函数库等) 1.3  shell shell是一个命令行解

APUE学习笔记:第二章 UNIX标准化及实现

2.2UNIX标准化 2.2.1 ISO C 国际标准化组织(International Organization for Standardization,ISO) 国际电子技术委员会(International Electrotechnical Commission,IEC) ISO C标准的意图是提供C程序的可移植性,使其能适合于大量不同的操作系统,而不只是UNIX系统.此标准不仅定义了C程序设计语言的语法和语义,还定义了其标准库.因为所有现今的UNIX系统都提供C标准中定义的库例程,所以该

o&#39;Reill的SVG精髓(第二版)学习笔记——第十一章

第十一章:滤镜 11.1滤镜的工作原理 当SVG阅读器程序处理一个图形对象时,它会将对象呈现在位图输出设备上:在某一时刻,阅读器程序会把对象的描述信息转换为一组对应的像素,然后呈现在输出设备上.例如我们用SVG的<filter>元素指定一组操作(也称作基元,primitive),在对象的旁边显示一个模糊的投影,然后把这个滤镜附加给一个对象: <fliter id="drop-shadow"> <!-- 这是滤镜操作 --> </fliter&g