select函数的使用

函数原型:

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select(int maxfdpl + 1, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *tvptr);

功能:用来监视  指定文件(使用文件描述符表示一个文件)的状态是否可 读(readfds),可写(writefds),异常(exceptfds)

参数:    
nfds:是要监视所有文件描述符中最大值 + 1  
 
readfds: 要监视可读文件描述符的集合,可以存放多个文件描述符号,一个位表示一个文件符号。
writefds:要监视可写文件描述符的集合
exceptfds: 要监视发生异常的文件描述符的集合
timeout:超时时间 
    NULL   表示如果所监视文件描述符中没有任何一个发生变化,无限循环监视
    timeval 成员全为0,表示,不管有没有变量,直接返回,不等待。
    timeval 成员不全为0,表示最多等待指定长的时间 ,这期间如果有任何一个变化了会返回。

return :

>0 准备就绪的描述符数目。表示状态发生变化的文件描述符数量。并不能表示具体是哪个发生了变化,需要【逐个】判断,使用 FD_ISSET(int fd, fd_set *set) 。

0   超时       

-1  出错

注意:
当 select 返回时候,它会集合中没有发生的变化的fd 对应 的位清0,发生变化的保持为1。
所以,每次 select 函数返回 后都要重新添加fd到集合中。

FD系列宏:

FD_ZERO(fd_set *fdset);//解除所有和描述符集的绑定(把集合中所有位设置为 0)

FD_SET(int fd, fd_set *fdset);//将相应的文件描述符集和药监听的描述符绑定 (把集合中下标为fd的位设置为 1 )

FD_ISSET(int fd, fd_set *fdset);//判断在监听的描述符是否可读,可写或者异常,返回值:若fd在文件描述符集中,返回非0值,否则返回0

FD_CLR(int fd, fd_set *fdset);//解除一个指定的文件描述符(把集合中下标为fd的位设置为 0 )

文件描述符号是一个数字。
fd_set 本质是一个 unsigned long 类型
#define __NFDBITS    (8 * sizeof(unsigned long))
#define __FD_SETSIZE    1024
#define __FDSET_LONGS    (__FD_SETSIZE/__NFDBITS)
typedef struct {
    unsigned long fds_bits [__FDSET_LONGS];  //定义一片连续的内存  ,位有一个编号  0,1,2,3,4…… 1023
} __kernel_fd_set;
typedef __kernel_fd_set        fd_set;

内核使用它的每个位表示 一个文件描述符号。

示例:如果要查询文件描述符为 1 和5的文件是否可读:

readfds  设置为  : 0010 0010   (二进制数量)
设置方法:
FD_SET(1, &readfds)   ;
FD_SET(5, &readfds)   ;

超时时间结构:
struct timeval {
    __kernel_time_t            tv_sec;        /* 秒 */
    __kernel_suseconds_t    tv_usec;    /* 微秒 */
};
应用层app的实例:


#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>

/*  程序启动时默认打开三个I/O设备文件:
 *   标准输入文件 stdin,标准输出文件stdout,标准错误输出文件stderr,分别得到文件描述符 0, 1, 2
 *  在标准输入读取9个字节数据。
 *   用select函数实现超时判断!
 */
int main(int argc, char ** argv)
{
  int ret;                  // return val
  char buf[1000] = {0};

  fd_set rdfds;

  printf("sizeof(fd_set):%d\n",sizeof(fd_set));   //查看数据类型的大小。128字节

  struct timeval tv; //store timeout

  while(1) {
    FD_ZERO(&rdfds);   //clear rdfds
    printf("befor set:%08x\n",rdfds);
    FD_SET(0, &rdfds);  //add stdin handle into rdfds
   FD_SET(2, &rdfds);  //for test
    printf("after set:%08x\n",rdfds);
    
    tv.tv_sec    = 3;
    tv.tv_usec  = 500;
    
    //如果文件调用出错,如文件描述符号不存在,则会直接返回 ,并不会清原来的rdfds,应用程序应该 判断
    ret = select(0 + 1, &rdfds, NULL, NULL, &tv);
    printf("return select:%08x\n",rdfds);
    if(ret < 0) {
      perror("\nselect");
      continue;
    } else if(ret == 0) {
      printf("\ntimeout");
      continue;
    } else {
      printf("\nret=%d", ret);
      if(FD_ISSET(0, &rdfds)) {
        printf("\nreading");
        fread(buf, 9, 1, stdin); // read form stdin
      }
      // read(0, buf, 9); /* read from stdin */
      // fprintf(stdout, "%s\n", buf); /* write to stdout */
      write(1, buf, strlen(buf)); //write to stdout
      //printf("\nlen:%d\n", strlen(buf));
      memset(buf,0,1000);
    }
  }
  return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值