关于select函数中struct timeval问题

21 篇文章 0 订阅
如果select调用中设置了等待时间,那么每次调用时都需要重新对这个时间赋值么?就像对fd_set处理一样。 
例如: 
fd_set readfd; 
struct timval tv; 
while(1) { 
  FD_ZERO(&readfd); 
  FD_SET(fd, &readfd); 
  tv.tv_sec = 2; 
  tv.tv_usec = 0; 
  select(maxfd+1, &readfd, NULL, NULL, &tv); 
  ......; 


如上代码,对fd_set需要每次调用都要重新设置,那么对tv来说是否也是一样呢?能不能把对tv的赋值放在while外面?
-------------------------------
之外意思就变了。
------------------------------
传的是一个引用进去,select里面可能会改变这个地址里保存的内容。所以每次循环都必须重新赋值
------------------------------
如楼主将时间的初始化放在外边,时间初始化为2秒,假设在1秒后发上了事件,则select将会返回并将tv的时间变成上次阻塞的剩余时间,即1秒,然后再进行监视套接字。这是因为linux系统对select()的实现中会修改参数tv为剩余时间。所以在循环内部使用函数select的时候一定要在循环内部初始化时间参数。
 
==================================================================
所以对于select函数中的最后一个参数,需要在循环中设置,每次循环要重新设置。如果设在循环外面,当循环执行起来后,每次循环select都会修改tv的值,tv的值越来越小,导致最后会产生select函数这tv时间内收不到有效时间,而返回-1,造成错误。
==================================================================
在网络程序中,一个进程同时处理多个文件描述符是很常见的情况。select()系统调用可以使进程检测同时等待的多个I/O设备, 当没有设备准备好时,select()阻塞,其中任一设备准备好时,select()就返回。
    这个函数真是神通广大,用来定时也不错。select(0, NULL, NULL, NULL, &tv)tv每次执行select前都要重新设定一遍,不然就变成0了。感觉它的精度比usleep()要高一些。

select()的调用形式为:
    #include <sys/select.h>
    #include <sys/time.h>
    int select(int maxfd, fd_set *readfds, fd_set *writefds, fe_set *exceptfds, const struct timeval *timeout);

    select的第一个参数是文件描述符集中要被检测的比特数,这个值必须至少比待检测的最大文件描述符大1;参数readfds指定了被读监控的文件描述符集;参数writefds指定了被写监控的文件描述符集;而参数exceptfds指定了被例外条件监控的文件描述符集。
    参数timeout起了定时器的作用:到了指定的时间,无论是否有设备准备好,都返回调用。timeval的结构定义如下:
    struct timeval{
        long tv_sec; //秒
        long tv_usec; //微秒
    }
    timeout取不同的值,该调用就表现不同的性质:
    timeout为0,调用立即返回;
    timeout为NULL,select()调用就阻塞,直到知道有文件描述符就绪;
    timeout为正整数,就是一般的定时器。
    select调用返回时,除了那些已经就绪的描述符外,select将清除readfds、writefds和exceptfds中的所有没有就绪的描述符。select的返回值有如下情况:
    正常情况下返回就绪的文件描述符个数;
    经过了timeout时长后仍无设备准备好,返回值为0;
    如果select被某个信号中断,它将返回-1并设置errno为EINTR。
    如果出错,返回-1并设置相应的errno。
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 socket 编程select 函数是一个非常重要的函数,它可以用于实现 I/O 多路复用,即同时监视多个文件描述符的可读、可写和错误事件。select 函数的原型如下: ```c int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); ``` 其,`nfds` 是需要监视的文件描述符最大的文件描述符加一;`readfds`、`writefds` 和 `exceptfds` 分别是需要监视的文件描述符集合,用于指定需要监视的文件描述符是否可读、可写或出现错误;`timeout` 是指定 select 函数的超时时间,如果为 NULL,则 select 函数将一直阻塞直到有事件发生。 当 select 函数返回时,可以通过检查 `readfds`、`writefds` 和 `exceptfds` 来确定哪些文件描述符上发生了可读、可写或错误事件。 select 函数的返回值表示就绪文件描述符的数量,如果超时则返回 0,如果出错则返回 -1。 需要注意的是,select 函数的参数的类型是 fd_set 结构体指针,而不是数组。fd_set 结构体是一个位图,每一位对应一个文件描述符,通过 FD_SET、FD_CLR、FD_ISSET 和 FD_ZERO 几个宏定义来操作 fd_set 结构体。在使用前需要调用 FD_ZERO 将 fd_set 结构体清零。 select 函数的使用可以参考以下伪代码: ```c fd_set read_fds; FD_ZERO(&read_fds); FD_SET(sock_fd, &read_fds); int max_fd = sock_fd + 1; while (1) { fd_set tmp_fds = read_fds; int ready_fd_cnt = select(max_fd, &tmp_fds, NULL, NULL, NULL); if (ready_fd_cnt < 0) { perror("select error"); break; } if (FD_ISSET(sock_fd, &tmp_fds)) { // 处理可读事件 // ... } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值