分类: LINUX
2010-09-28 17:35:21
19.处理套接口的fcntl函数
#include
int fcntl(int fd, int cmd, … /* arg */);
返回:依赖于参数cmd—成功,-1—失败。
函数fcntl提供了如下关于网络编程的特性:
1. 非阻塞I/O:通过用F_SETFL命令设置O_NONBLOCK文件状态标志来设置套接口为非阻塞型。
2. 信号驱动I/O:用F_SETFL命令来设置O_ASYNC文件状态标志,这导致在套接口状态发生变化时内核生成信号SIGIO。
3. F_SETOWN命令设置套接口属主(进程ID或进程组ID),由它来接收信号SIGIO和SIGURG。SIGIO在设置套接口为信号驱动I/O型时生成,SIGURG在新的带外数据到达套接口时生成。
4. F_GETOWN命令返回套接口的当前属主。
注意事项:
· 设置某个文件状态标志时,先取得当前标志,与新标志路逻辑或后再设置标志。
· 信号SIGIO和SIGURG与其他信号不同之处在于,这两个信号只有在已使用命令F_SETOWN给套接口指派了属主后才会生成。F_SETOWN命令的整参数arg既可以是一个正整数,指明接收信号的进程ID,也可以是一个负整数,它的绝对值是接收信号的进程组ID。
· 当一个新的套接口由函数socket创建时,他没有属主,但是当一个新的套接口从一个监听套接口创建时,套接口属主便由已连接套接口从监听套接口继承而来。
20.gethostbyname函数
#include
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设置为定义在头文件
· 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
struct hostent *gethostbyname2(const char *hostname, int family);
返回:非空指针—成功,空指针—出错,同时设置h_errno。
该函数允许指定地址族,其他与gethostbyname相似。
22.gethostbyaddr函数
#include
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记录。
23.uname函数
#include
int uname(struct utsname *name);
返回:非负值—成功,-1—失败。
返回当前主机的名字,存放在如下的结构里:
#define UTS_NAMESIZE 16
#define UTS_NODESIZE 256
struct 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。
24.gethostname函数
#include
int gethostname(char *name, size_t namelen);
返回:0—成功,-1—失败。
返回当前主机的名字。name是指向主机名存储位置的指针,namelen是此数组的大小,如果有空间,主机名以空字符结束。
主机名的最大大小通常是头文件
25.getservbyname函数
#include
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。
26.getservbyport函数
#include
struct servent *getservbyport(int port, const char *protname);
返回:非空指针—成功,空指针—出错。
port必须为网络字节序。例如:
sptr = getservbyport(htons(53), “udp”);
27.recv和send
#include
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)在套接口上发生错误,这个函数返回的字节数仍会比请求的少。
28.readv和writev
#include
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算法。
29.readmsg和writemsg
#include
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、 |
在recv 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的标志,所以我们应该只检查那些感兴趣的标志的值。
管理员在2009年8月13日编辑了该文章文章。
chinaunix网友2010-09-29 12:55:12
很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com
chinaunix网友2010-09-29 12:55:01
很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com