首页 > 代码库 > UNIX网络编程-基本API介绍(二)
UNIX网络编程-基本API介绍(二)
参考链接:http://www.cnblogs.com/riky/archive/2006/11/24/570713.aspx
1、getsockname和getpeername
getsockname函数获取与套接口关联的本地协议地址。
getpeername函数获取与套接口关联的远程协议地址。
----------------------------------------------------------------------
#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
int getpeername(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
返回:0 成功;-1 失败。
----------------------------------------------------------------------
使用场合:
在不调用bind的TCP客户,当connect成功返回后,getsockname返回分配给此连接的本地IP地址和本地端口号;
在以端口号为0调用bind后,使用getsockname返回内核分配的本地端口号;
getsockname可用来获取某套接口的地址族;
在捆绑了通配IP地址的TCP服务器上,当连接建立后,可以使用getsockname获得分配给此连接的本地IP地址;
当一个服务器调用exec启动后,他获得客户身份的唯一途径是调用getpeername函数。
2、select
----------------------------------------------------------------------
#include <sys/select.h>
#include <sys/time.h>
int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout);
返回:准备好描述字的正数目,0—超时,-1—出错。
----------------------------------------------------------------------
2.1 结构timeval的定义:
struct timeval{ long tv_sec; /* seconds */ long tv_usec; /* microseconds */};
2.2 timeout取值的三种情况:
永远等下去:仅在有一个描述字准备好I/O时才返回,设置timeout为空指针;
等待固定时间:在有一个描述字准备好I/O时返回,但不超过由timeout参数所指定的秒数和微秒数;
根本不等待:检查描述字后立即返回,将timeout中的秒数和微秒数都设置为0。
在等待过程中,若进程捕获了信号并从信号处理程序返回,等待一般被中断,为了可移植性,必须准备好select返回EINTR错误。
timeout的值在返回时并不会被select修改(const标志)。
2.3 readset、writeset、exceptset是内核测试读、写和异常条件所需的描述字。
当前支持的异常条件有两个:
套接口带外数据的到达;
控制状态信息的存在,可从一个已置为分组方式的伪终端主端读到。
描述字集的使用:
数据类型:fd_set;
void FD_ZERO(fd_set *fdset);
void FD_SET(int fd, fd_set *fdset);
void FD_CLR(int fd, fd_set *fdset);
void FD_ISSET(int fd, fd_set *fdset);
参数maxfdp1指定被测试的描述字个数,它的值是要被测试的最大描述字加1。描述字0,1,2,…,maxfdp1-1都被测试。
readset、writeset、exceptset是值-结果参数,select修改三者所指的描述字集。所以,每次调用select时,我们都要将所有描述字集中关心的位置为1。
2.4 套接口准备好读的条件:
套接口接收缓冲区中的数据字节数大于等于套接口接收缓冲区低潮限度的当前值。对这样的套接口的读操作将不阻塞并返回一个大于0的值(即准备好读入的数据量)。可以用套接口选项SO_RCVLOWAT来设置低潮限度,对于TCP和UDP,缺省值为1;
连接的读这一半关闭(接收了FIN的TCP连接)。对这样的套接口读操作将不阻塞并且返回0(即文件结束符);
套接口是一个监听套接口且已完成的连接数为非0;
有一个套接口错误待处理。对这样的套接口读操作将不阻塞且返回一个错误,errno设置成明确的错误条件。这些待处理错误也可以通过指定套接口选项SO_ERROR调用getsockopt来取得并清除。
2.5 套接口准备好写的条件:
套接口发送缓冲区中的可用字节数大于等于套接口发送缓冲区低潮限度的当前值,且或者(1)套接口已连接,或者(2)套接口不要求连接(如UDP套接口)。可以用套接口选项SO_SNDLOWAT来设置此低潮限度,对于TCP和UDP,缺省值为2048;
连接的写这一半关闭。对这样的套接口写将产生信号SIGPIPE;
有一个套接口错误待处理。对这样的套接口写操作将不阻塞且返回一个错误,errno设置成明确的错误条件。这些待处理错误也可以通过指定套接口选项SO_ERROR调用getsockopt来取得并清除。
如果一个套接口存在带外数据或者仍处于带外标记,那它有异常条件待处理。
一个套接口出错时,它被select标记为既可读又可写。
3、shutdown
----------------------------------------------------------------------
#include <sys/socket.h>
int shutdown(int sockfd, int howto);
返回:0 成功,-1 失败。
----------------------------------------------------------------------
函数的行为依赖于参数howto的值:
SHUT_RD:关闭连接的读这一半,不再接收套接口中的数据且留在套接口缓冲区中的数据都作废。进程不能再对套接口任何读函数。调用此函数后,由TCP套接口接收的任何数据都被确认,但数据本身被扔掉。
SHUT_WR:关闭连接的写这一半,在TCP场合下,这称为半关闭。当前留在套接口发送缓冲区中的数据都被发送,后跟正常的TCP连接终止序列。此半关闭不管套接口描述字的访问计数是否大于0。进程不能再执行对套接口的任何写函数。
SHUT_RDWR:连接的读这一半和写这一半都关闭。这等效于调用shutdown两次:第一次调用时用SHUT_RD,第二次调用时用SHUT_WR。
4、pselect
----------------------------------------------------------------------
#include <sys/select.h>
#include <signal.h>
#include <time.h>
int pselect(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timespec *timeout, const sigset_t *sigmask);
返回:准备好描述字的个数,0—超时,-1—出错。
----------------------------------------------------------------------
pselect是Posix.1g发明的。相对select的变化:
pselect使用结构timespec:
struct timespec
{
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
新结构中的tv_nsec规定纳秒数。
pselect增加了第六个参数:指向信号掩码的指针。允许程序禁止递交某些信号。
5、poll
----------------------------------------------------------------------
#include <poll.h>
int poll(struct pollfd *fdarray, unsigned long nfds, int timeout);
返回:准备好描述字的个数,0—超时,-1—出错。
----------------------------------------------------------------------
5.1 pollfd结构
第一个参数是指向一个结构数组的第一个元素的指针,每个数组元素都是一个pollfd结构:
struct pollfd
{
int fd; /* descriptor to check */
short events; /* events of interest on fd */
short revents; /* events that occurred on fd */
};
要测试的条件由成员events规定,函数在相应的revents成员中返回描述字的状态(一个描述字有两个变量:一个为调用值,一个为结果)。
5.2 第二个参数指定数组中元素的个数。
5.3 第三个参数timeout。
指定函数返回前等待多长时间,单位是毫秒。可能值如下:
INFTIM,永远等待;
0,立即返回,不阻塞;
>0,等待指定数目的毫秒数。
5.4 标志的范围:
常量 | 能作为events的输入吗? | 能作为revents的结果吗? | 解释 |
POLLIN | yes | yes | 普通或优先级带数据可读 |
POLLRDNORM | yes | yes | 普通数据可读 |
POLLRDBAND | yes | yes | 优先级带数据可读 |
POLLPRI | yes |
| 高优先级数据可读 |
POLLOUT | yes | yes | 普通或优先级带数据可写 |
POLLWRNORM | yes | yes | 普通数据可写 |
POLLWRBAND | yes | yes | 优先级带数据可写 |
POLLERR |
| yes | 发生错误 |
POLLHUP |
| yes | 发生挂起 |
POLLNVAL |
| yes | 描述字不是一个打开的文件 |
图表可分为三部分:处理输入的四个常值;处理输出的三个常值;处理错误的三个值。
poll识别三个类别的数据:普通(normal)、优先级带(priority band)、高优先级(high priority)。术语来自流的概念。
5.5 返回条件:
所有正规TCP数据和UDP数据都被认为是普通数据;
TCP的带外数据被认为是优先级带数据;
当TCP连接的读这一半关闭时(如接收了一个FIN),这也认为是普通数据,且后续的读操作将返回0;
TCP连接存在错误既可以认为是普通数据,也可以认为是错误(POLLERR)。无论哪种情况,后续的读操作将返回-1,并将errno置为适当的值,这就处理了诸如接收到RST或超时等条件;
在监听套接口上新连接的可用性既可认为是普通数据,也可以认为是优先级带数据,大多数实现都将其作为普通数据考虑。
如果不关心某个特定的描述字,可将其pollfd结构的fd成员置为一个负值,这样就可以忽略成员events,且返回时将成员revents的值置为0。
poll没有select存在的最大描述字数目问题。但可移植性select要好于poll。
6、getsockopt和setsockopt
----------------------------------------------------------------------
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
返回:0—OK,-1—出错。
----------------------------------------------------------------------
sockfd必须是一个打开的套接口描述字;level(级别)指定系统中解释选项的代码:普通套接口代码或特定于协议的代码);optval是一个指向变量的指针;此变量的大小由最后一个参数决定。
对于某些套接口选项,什么时候进行设置或获取是有差别的。下面的套接口选项是由TCP已连接套接口从监听套接口继承来的:
SO_DEBUG;
SO_DONTROUTE;
SO_KEEPALIVE;
SO_LINGER;
SO_OOBINLINE;
SO_RCVBUF;
SO_SNDBUF。
如果想在三路握手完成时确保这些套接口选项中的某一个是给已连接套接口设置的,我们必须先给监听套接口设置此选项。
7、处理套接口的fcntl函数
----------------------------------------------------------------------
#include <fcntl.h>
int fcntl(int fd, int cmd, … /* arg */);
返回:依赖于参数cmd—成功,-1—失败。
----------------------------------------------------------------------
函数fcntl提供了如下关于网络编程的特性:
非阻塞I/O:通过用F_SETFL命令设置O_NONBLOCK文件状态标志来设置套接口为非阻塞型。
信号驱动I/O:用F_SETFL命令来设置O_ASYNC文件状态标志,这导致在套接口状态发生变化时内核生成信号SIGIO。
F_SETOWN命令设置套接口属主(进程ID或进程组ID),由它来接收信号SIGIO和SIGURG。SIGIO在设置套接口为信号驱动I/O型时生成,SIGURG在新的带外数据到达套接口时生成。
F_GETOWN命令返回套接口的当前属主。
注意事项:
设置某个文件状态标志时,先取得当前标志,与新标志路逻辑或后再设置标志。
信号SIGIO和SIGURG与其他信号不同之处在于,这两个信号只有在已使用命令F_SETOWN给套接口指派了属主后才会生成。F_SETOWN命令的整参数arg既可以是一个正整数,指明接收信号的进程ID,也可以是一个负整数,它的绝对值是接收信号的进程组ID。
当一个新的套接口由函数socket创建时,他没有属主,但是当一个新的套接口从一个监听套接口创建时,套接口属主便由已连接套接口从监听套接口继承而来。
8、gethostbyname
----------------------------------------------------------------------
#include <netdb.h>
struct hostent *gethostbyname(const char *hostname);
返回:非空指针—成功,空指针—出错,同时设置h_errno。
----------------------------------------------------------------------
函数返回的非空指针指向的结构如下:
struct hostent {
char *h_name; /*规范主机名 */
char **h_aliases; /* 别名列表 */
int h_addrtype; /* AF_INET or AF_INET6 */
int h_length; /* 地址长度 */
char **h_addr_list; /* IPv4或IPv6地址结构列表 */
};
#define h_addr h_addr_list[0];
按照DNS的说法,gethostbyname执行一个对A记录的查询或对AAAA记录的查询,返回IPv4或IPv6地址。
h_addr的定义是为了兼容,在新代码中不应使用。
返回的h_name称为主机的规范(canonical)名字。当返回IPv6地址时,h_addrtype被设置为AF_INET6,成员h_length被设置为16。
gethostbyname的特殊之处在于:当发生错误时,他不设置errno,而是将全局整数h_errno设置为定义在头文件<netdb.h>中的下列常值中的一个:
HOST_NOT_FOUND;
TRY_AGAIN;
NO_RECOVERY;
NO_DATA(等同于NO_ADDRESS)。
有函数hstrerror(),它将h_errno的值作为唯一的参数,返回一个指向相应错误说明的const char *型指针。
DNS小常识:
DNS中的条目称为资源记录RR(resource record),仅有少数几类RR会影响我们的名字与地址转换:
A:A记录将主机名映射为32位的IPv4地址;
AAAA:“四A”记录将主机名映射为128位的IPv6地址;
PTR:PTR记录(称为“指针记录”)将IP地址映射为主机名;
MX:MX记录指定一主机作为某主机的“邮件交换器”。
CNAME:CNAME代表“canonical name(规范名字)”,其常见的用法是为常用服务如ftp和www指派一个CNAME记录。
21.gethostbyname2函数
#include <netdb.h>
struct hostent *gethostbyname2(const char *hostname, int family);
返回:非空指针—成功,空指针—出错,同时设置h_errno。
该函数允许指定地址族,其他与gethostbyname相似。
9、gethostbyaddr
----------------------------------------------------------------------
#include <netdb.h>
struct hostent *gethostbyaddr(const char *addr, size_t len, int family);
返回:非空指针—成功,空指针—出错,同时设置h_error。
----------------------------------------------------------------------
函数根据一个二进制的IP地址并试图找出相应于此地址的主机名,我们关心的是规范主机名h_name。
参数addr不是char *类型,而是一个真正指向含有IPv4或IPv6地址的结构in_addr或in6_addr的指针;len是该结构的大小,对于IPv4是4,对于IPv6是16;family或为AF_INET或为AF_INET6。
按照DNS的说法,该函数查询PTR记录。
10、uname函数
----------------------------------------------------------------------
#include <sys/utsname.h>
int uname(struct utsname *name);
返回:非负值—成功,-1—失败。
----------------------------------------------------------------------
返回当前主机的名字,存放在如下的结构里:
#define UTS_NAMESIZE 16#define UTS_NODESIZE 256struct utsname{ char sysname[UTS_NAMESIZE]; char nodename[UTS_NODESIZE]; char release[UTS_NAMESIZE]; char version[UTS_NAMESIZE]; char machine[UTS_NAMESIZE];};
该函数经常与gethostbyname一起用来确定本机的IP地址:先调用uname获得主机名字,然后调用gethostbyname得到所有的IP地址。
获得本机IP地址的另一个方法是ioctl的命令SIOCGIFCONF。
11、gethostname函数
----------------------------------------------------------------------
#include <unistd.h>
int gethostname(char *name, size_t namelen);
返回:0—成功,-1—失败。
----------------------------------------------------------------------
返回当前主机的名字。name是指向主机名存储位置的指针,namelen是此数组的大小,如果有空间,主机名以空字符结束。
主机名的最大大小通常是头文件<sys/param.h>定义的常值MAXHOSTNAMELEN。
12、getservbyname函数
----------------------------------------------------------------------
#include <netdb.h>
struct servent *getservbyname(const char *servname, const char *protoname);
返回:非空指针—成功,空指针—失败。
----------------------------------------------------------------------
函数返回如下结构的指针:
struct servent{ char *s_name; char **s_aliases; int s_port; char *s_proto;};
服务名servname必须指定,如果还指定了协议(protoname为非空指针),则结果表项必须有匹配的记录。如果没有指定协议名而服务支持多个协议,则返回哪个端口是依赖于实现的。
结构中的端口号是以网络字节序返回的,所以在将它存储在套接口地址结构时,绝对不能调用htons。
13、getservbyport函数
----------------------------------------------------------------------
#include <netdb.h>
struct servent *getservbyport(int port, const char *protname);
返回:非空指针—成功,空指针—出错。
----------------------------------------------------------------------
port必须为网络字节序。例如:
sptr = getservbyport(htons(53), “udp”);
14、recv和send
----------------------------------------------------------------------
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);
ssize_t send(int sockfd, void *buf, size_t nbytes, int flags);
返回:成功返回读入或写出的字节数,出错返回-1。
----------------------------------------------------------------------
前三个参数与read和write相同,参数flags的值或为0,或由以下的一个或多个常值逻辑或构成:
flags 描述 recv send
MSG_DONTROUTE 不查路由表 y
MSG_DONTWAIT 本操作不阻塞 y y
MSG_OOB 发送或接收带外数据 y y
MSG_PEEK 查看外来的消息 y
MSG_WAITALL 等待所有数据 y
下面说明每个标志的作用:
MSG_DONTROUTE:这个标志告诉内核目的主机在直接连接的本地网络上,不要查路由表。这是对提供这种特性的SO_DONTROUTE套接口选项的补充。该标志可以对单个输出操作提供这种特性,而套接口选项则针对某个套接口上的所有输出操作。
MSG_DONTWAIT:这个标志将单个I/O操作设为非阻塞方式,而不需要在套接口上打开非阻塞标志,执行I/O操作,然后关闭阻塞标志。
MSG_OOB:用send时,这个标志指明发送的是带外数据,用recv时,该标志指明要读的是带外数据而不是一般数据。
MSG_PEEK:这个标志可以让我们查看可读的数据,在recv或recvfrom后系统不会将这些数据丢弃。
MSG_WAITALL:由4.3BSD Reno引入,他告诉内核在没有读到请求的字节数之前不使读操作返回。如果系统支持这个标志,则可以去掉readn函数。即使设定了该标志 ,如果发生如下情况:(1)捕获了一个信号;(2)连接被终止;(3)在套接口上发生错误,这个函数返回的字节数仍会比请求的少。
15、readv和writev
----------------------------------------------------------------------
#include <sys/uio.h>
ssize_t readv(int filedes, const struct iovec *iov, int iovcnt);
ssize_t writev(int filedes, const struct iovec *iov, int iovcnt);
返回:读到或写出的字节数,出错返回-1。
----------------------------------------------------------------------
readv和writev可以让我们在一个函数调用中读或写多个缓冲区,这些操作被称为分散读和集中写。
iovec结构定义如下:
struct iovec{ void *iov_base; /* starting address of buffer */ size_t iov_len; /* size of buffer */};
在具体的实现中对iovec结构数组的元素个数有限制,4.3BSD最多允许1024个,而Solaris2.5上限是16。Posix.1g要求定义一个常值IOV_MAX,而且它的值不小于16。
readv和writev可用于任何描述字。writev是一个原子操作,可以避免多次写引发的Nagle算法。
16、readmsg和writemsg
----------------------------------------------------------------------
#include <sys/socket.h>
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags);
返回:成功时为读入或写出的字节数,出错时为-1。
----------------------------------------------------------------------
这两个函数是最通用的套接口I/O函数,可以用recvmsg代替read、readv、recv和recvfrom,同样,各种输出函数都可以用sendmsg代替。
参数msghdr结构的定义如下:
struct msghdr { void *msg_name; /* protocol address */ socklen_t msg_namelen; /* size of protocol address */ struct iovec *msg_iov; /* scatter/gather array */ size_t msg_iovlen; /* elements in msg_iov */ void *msg_control; /* ancillary data; must be aligned for a cmsghdr structure */ socklen_t msg_controllen; /* length of ancillary data */ int msg_flags; /* flags returned by recvmsg() */};
该结构源自4.3BSD Reno,也是Posix.1g中所说明的,有些系统仍使用一种老的msghdr结构,此种结构中没有msg_flags成员,而且msg_control和msg_controllen成员分别被叫做msg_accrights和msg_accrightslen。老系统中支持的唯一一种辅助数据形式是文件描述字(称为访问权限)的传递。
msg_name和msg_namelen成员用于未经连接的套接口,他们与recvfrom和sendto的第五和第六个参数类似:msg_name指向一个套接口地址结构,如果不需要指明协议地址,msg_name应被设置为空指针,msg_namelen对sendmsg是一个值,而对recvmsg是一个值-结果参数。
msg_iov和msg_iovlen成员指明输入或输出的缓冲区数组。
msg_control和msg_controllen指明可选的辅助数据的位置和大小,msg_controllen对recvmsg是一个值-结果参数。
msg_flags只用于revmsg,调用recvmsg时,flags参数被拷贝到msg_flags成员,而且内核用这个值进行接收处理,接着它的值会根据recvmsg的结果而更新,sendmsg会忽略msg_flags成员,因为它在进行输出处理时使用flags参数。
内核检查的flags和返回的msg_flags如下表所示:
标志 在send flags、
sendto flags、
sendmsg flags中检查 在recv flags、
recvfrom flags、
recvmsg flags中检查 在recvmsg msg_flags
中返回
MSG_DONTROUTE y
MSG_DONTWAIT y y
MSG_PEEK y
MSG_WAITALL y
MSG_EOR y y
MSG_OOB y y y
MSG_BCAST y
MSG_MCAST y
MSG_TRUNC y
MSG_CTRUNC y
前四个标志只检查不返回,下两个标志既检查又返回,最后四个只返回。返回的六个标志含义如下:
MSG_BCAST:当收到的数据报是一个链路层的广播或其目的IP地址为广播地址时,将返回此标志。
MSG_MCAST:当收到的数据报是链路层的多播时,将返回该标志。
MSG_TRUNC:这个标志在数据报被截断时返回。
MSG_CTRUNC:这个标志在辅助数据被截断时返回。
MSG_EOR:如果返回的数据不是一个逻辑记录的结尾,该标志被清位,反之则置位。TCP不使用这个标志,因为它是一种字节流协议。
MSG_OOB:这个标志不是为TCP的带外数据返回的,它用于其他协议族(譬如OSI协议等)。
具体的实现可能会在msg_flags中返回一些输入的flags的标志,所以我们应该只检查那些感兴趣的标志的值。
17、socketpair函数
----------------------------------------------------------------------
#include <sys/socket.h>
int socketpair(int family, int type, int protocol, int sockfd[2]);
返回:成功返回0,出错返回-1。
----------------------------------------------------------------------
family必须为AF_LOCAL,protocol必须为0,type可以是SOCK_STREAM或SOCK_DGRAM。新创建的两个套接口描述字作为sockfd[0]和sockfd[1]返回。
这两个描述字相互连接,没有名字,即没有涉及隐式bind。
以SOCK_STREAM作为type调用所得到的结果称为流管道(stream pipe)。这与一般的UNIX管道类似,但流管道是全双工的,两个描述字都是可读写的。
18、套接口ioctl函数
----------------------------------------------------------------------
#include <unistd.h>
int ioctl(int fd, int request, … /* void *arg */ );
返回:成功返回0,出错返回-1。
----------------------------------------------------------------------
第三个参数总是一个指针,但指针的类型依赖于request。
ioctl和网络有关的请求可分为如下6类:
类别 request 描述 数据类型
套接口 SIOCATMARK 在带外标志上吗 int
SIOCSPGRP 设置套接口的进程ID或进程组ID int
SIOCGPGRP 获取套接口的进程ID或进程组ID int
文件 FIONBIO 设置/清除非阻塞标志 int
FIOASYNC 设置/清除异步I/O标志 int
FIONREAD 获取接收缓冲区中的字节数 int
FIOSETOWN 设置文件的进程ID或进程组ID int
FIOGETOWN 获取文件的进程ID或进程组ID 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 获取接口的测度(metric) struct ifreq
SIOCSIFMETRIC 设置接口的测度(metric) struct ifreq
SIOCxxx (有很多,依赖于实现)
ARP SIOCSARP 创建/修改ARP项 struct arpreq
SIOCGARP 获取ARP项 struct arpreq
SIOCDARP 删除ARP项 struct arpreq
路由 SIOCADDRT 增加路径 struct rtentry
SIOCDELRT 删除路径 struct rtentry
流 I_xxx
18.1 套接口操作
SIOCATMARK:如果套接口的读指针当前在带外标志上,则通过第三个参数指向的整数返回一个非零值,否则返回零。Posix.1g用sockatmark代替了这种请求。
SIOCGPGRP:通过第三个参数指向的整数返回为接收来自这个套接口的SIGIO或SIGURG信号而设置的进程ID或进程组ID。这和fcntl的F_GETOWN相同。
SIOCSPGRP:用第三个参数指向的整数设置进程ID或进程组ID以接收这个套接口的SIGIO或SIGURG信号。这和fcntl的F_SETOWN相同。
18.2 文件操作
FIONBIO:套接口的非阻塞标志会根据第三个参数指向的值是否为零而清除或设置。等价于fcntl的F_SETFL设置/清除O_NONBLOCK标志。
FIOASYNC:根据第三个参数指向的值是否为零决定清除或接收套接口上的异步I/O信号。等价于fcntl的F_SETFL设置和清除O_AYNC标志。
FIONREAD:在第三个参数指向的整数中返回套接口接收缓冲区中当前的字节数。
FIOSETOWN:在套接口上等价于SIOCSPGRP。
FIOGETOWN:在套接口上等价于SIOCGPGRP。
18.3 接口配置
SIOCGIFCONF:从内核中获取系统中配置的所有接口。它使用了结构ifconf,ifconf又使用了ifreq结构。
结构定义如下:
struct ifconf{ int ifc_len; /* size of buffer, value-result */ union { caddr_t ifcu_buf; /* input from user->kernel */ struct ifreq *ifcu_req; /* return from kernel->user */ }ifc_ifcu;};#define ifc_buf ifc_ifcu.ifcu_buf#define ifc_req ifc_ifcu.ifcu_req#define IFNAMSIZ 16struct 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.broadaddr#define ifr_flags ifr_ifru.ifru_flags#define ifr_metric ifr_ifru.ifru_metric#define ifr_data ifr_ifru.ifru_data
在调用ioctl之前分配一个缓冲区和一个ifconf结构,然后初始化后者,iotctl的第三个参数指向ifconf结构。
一个实现获取所有接口的程序,可参见unpv12e:lib/get_ifi_info.c
18.4 接口操作
SIOCGIFCONF:从内核中获取系统中配置的所有接口。
18.5 ARP高速缓存操作
18.6 路由表操作