您的位置:首页 > 其它

基于select模型的udp客户端实现超时机制

2014-02-18 21:07 489 查看
多路选择I/O — select模型

其思想在于使用一个集合,该集合中包含需要进行读写的fd,通过轮询这个集合,直到有一个fd可读写,才返回。与阻塞I/O不同的是,阻塞I/O仅使用了一次系统调用,就是对fd的读写,如果没有fd处于就绪状态,则进程一直阻塞,而多路选择I/O使用了两次系统调用,第一次是轮询并返回可读写fd数,第二次是对fd进行读写,阻塞只发生在轮询fd的过程。

select函数的原型(sys/select.h)

int select (int __nfds, fd_set *__restrict __readfds,
fd_set *__restrict __writefds,
fd_set *__restrict __exceptfds,
struct timeval *__restrict __timeout);


(1)__nfds

    需轮询的最大文件描述符数。如__nfds = 10,则轮询值为0~9的fd,单个进程中,最多可打开1024个fd,该值在sys/select.h中的FD_SETSIZE定义。用户可通过“ulimit -n”查看该值,通过打印/proc/sys/fs/file-max中的值查看系统可打开的最大fd数。



(2)__readfds,__writefds,__exceptfds

    分别代表用户关心的可读、可写、异常的fd,这三个参数的数据类型是fd_set *,这是一组文件描述符的集合,使用一个位来代表一个fd。



fd_set位向量操作函数包括

#define FD_SET(fd, fdsetp)   __FD_SET (fd, fdsetp)   //将指定的fd置1
#define FD_CLR(fd, fdsetp)   __FD_CLR (fd, fdsetp)   //将指定的fd清0
#define FD_ISSET(fd, fdsetp) __FD_ISSET (fd, fdsetp) //测试fd状态,如被置1,返回非0,否则返回0
#define FD_ZERO(fdsetp)      __FD_ZERO (fdsetp)      //将所有的fd清0


(3)__timeout

    timeout的数据类型是timeval结构体。通过填充该结构体,设置超时时间,精确到微妙级,如果该参数设置为NULL,则一直等待,直到有fd可读写。如果tv_sec和tv_usec都设置为0,则轮询完指定fd后,立即返回。

struct timeval
{
__time_t tv_sec;          /* Seconds.  */
__suseconds_t tv_usec;    /* Microseconds.  */
};


(4)select有三种返回值

-1 :出错

0 :如果设置了超时,在指定时间内没有fd可读写,则返回0,可在此指定相应的超时处理操作。

>0 :返回可读写的fd数

可屏蔽信号的select — pselect

从原型上看,pselect函数与select函数的区别在于设置超时的结构体不同,以及多了个用于屏蔽信号的参数。如果__sigmask设置为NULL,则与select一样。

int pselect (int __nfds, fd_set *__restrict __readfds,
fd_set *__restrict __writefds,
fd_set *__restrict __exceptfds,
const struct timespec *__restrict __timeout,
const __sigset_t *__restrict __sigmask);


(1)timespec结构体的定义如下,它精确到纳秒级。

struct timespec
{
__time_t tv_sec;         /* Seconds.  */
long int tv_nsec;        /* Nanoseconds.  */
};


(2)__sigmask实际上是信号的位向量。数据类型是sigset_t,定义如下

/* A `sigset_t' has a bit for each signal.  */

# define _SIGSET_NWORDS    (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{
unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;


模型示例代码如下:

int maxfdp,sockfd;
fd_set fds;
struct timeval timeout;
int interval = 3;

while (1) {

timeout.tv_usec = 0;
timeout.tv_sec = interval;

FD_ZERO(&fds);
FD_SET(sockfd, &fds);
maxfdp = sockfd + 1;
sendto();

switch(select(maxfdp, &fds, NULL, NULL, &timeout)) {
case -1:
exit(-1);
break;

case 0:
break;

default:
if(FD_ISSET(fd, &fds)) {
revcfrom();
}
break;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: