在套接口上设置超时有三种方法:
1,调用alarm,它在指定超时期满时产生SIGALRM信号。不过需要注意的是,在多线程化程序中,正确使用信号却非常困难。因此建议只在未线程化的单线程程序中使用此技术。
2,在select中阻塞等待I/O,由于select有时间限制,并且它比alarm更精确,所以可以以此代替直接阻塞在read或write上的调用。它适合于任意类型的套接口。
3,使用SO_RECVTIMEO和SO_SNDTIMEO套接口,这个方法的问题在于并非所有的实现都支持这两个套接口选项。这两个选项一旦用于设置某个描述字,其超时设置将应用于该描述字上的所有读/写操作,而前两个方法总是要求在欲设置时间限制的每个操作发生之前做些工作。
recv和send函数
#include
ssize_t recv( int sockfd, void *buf, size_t nbyte, int flags );
ssize_t send( int sockfd, void *buf, size_t nbyte, int flags );
这与标准的read和write函数类似,只是多了一个额外的参数flags,其值为0或者以下值的逻辑或。
MSG_DONTROUTE 本标志告知内核宿主机在某个直接连接的本地网络上,因而无需执行路由表查找。
MSG_DONTWAIT 本标志在无需打开相应套接口的非阻塞标志的前提下,把单个I/O操作临时指定为非阻塞, 接着执行I/O操作,然后关闭非阻塞标志。这个标志是Net/3新增加的,可能并非所有系统都支持。
MSG_OOB 对于send,本标志指明即将发送带外数据,对于recv,本标志指明即将读入的是带外数据而不是普通数据。
MSG_PEEK 本标志适用于recv和redvfrom,它允许我们窥看已可读取的数据,不过系统不丢弃由recv或recvform窥看走的数据。
MSG_WAITALL 它告知内核不要在尚未读入请求数目的字节之前让一个读操作返回。即使指定了此标志,如果发生下列情况之一:捕获一个信号;连接被终止;套接口发生一个错误;相应的读函数仍有可能返回比所请求字节数要少的数据。
flags参数设计上存在一个问题:它是按值传递的,而不是一个值-结果参数。因此它只能用于从进程到内核传递标志,内核无法向进程传回标志。这对于TCP/IP协议不成问题,但是对于OSI协议提出了随输入操作向进程返送MSG_EOR标志的需求,它变得不合适宜。如果一个进程需要由内核更新标志,它就必须调用recvmsg,而不能调用recv或recvfrom。
在介绍recvmsg之前,先来看看另外两个函数:
#include
ssize_t readv( int filedes, const struct iovec *iov, int iovcnt );
ssize_t writev( int filedes, const struct iovec *iov, int iovcnt );
struct iovec {
void *iov_base; /* starting address of buffer */
size_t iov_len; /* size of buffer */
};
这两个操作分别叫着分散读(scatter read)和集中写(gather write),因为来自读操作的输入数据被分散到多个应用缓冲区中,而来自多个应用缓冲区的输出数据则被集中提供给单个写操作。这两个操作可用于任何描述字。
recvmsg和sendmsg
这两个函数是最通用的I/O函数,实际上,我们可以把所有read,readv,recv和recvfrom调用替换成recvmsg,类似的输出调用替换成sendmsg。
#include
ssize_t recvmsg( int sockfd, struct msghdr *msg, int flags );
ssize_t sendmsg( int sockfd, struct msghdr *msg, int falgs );
struct msghdr {
void *msg_name; /*protocol address*/
socklen_t msg_namelen; /*size of protocol address*/
struct iovec *msg_iov; /* scatter/gather array */
int msg_iovlen; /*elements in msg_iov*/
void *msg_control; /*ancillary data (cmsghdr struct)*/
socklen_t msg_controllen; /* length of ancillary data */
int msg_flags; /*flags returned by recvmsg*/
};
msg_name和mag_namelen这两个成员用于套接口未连接的场合,它们类似于recvfrom和sendto的第5个和第6个成员。msg_iov和msg_iovlen这两个成员指定输入或输出缓冲区数组。msg_control和msg_controllen这两个成员指定可选的辅助数据的位置和大小。
对于recvmsg和sendmsg,我们必须区别它们的两个标志变量:一个是传递值的flags参数,另一个是所传递msghdr结构的msg_flags成员,它传递的是引用,因为传递给函数的是该结构的地址。只有recvmsg使用msg_flags成员。recvmsg被调用时,flags参数被拷贝到msg_flags成员,并由内核使用其值驱动接收处理过程,内核还依据recvmsg的结果更新msg_flags成员的值。sendmsg忽略msg_flags成员,因为它直接使用flags参数驱动发送处理过程。
阅读(1612) | 评论(0) | 转发(0) |