linux io复用之select

文章内容参考:linux高性能服务器编程
I/O复用虽然能同时监听多个文件描述符, 但是它本身是阻塞的。并且当多个文件描述符同时就绪时,如果不采取额外的措施,程序,就只能按照顺序依次处理其中的每一个描述符。
select原型

     #include <sys/select.h>
     int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout );

参数解释
1)nfds参数指定被监听的文件描述符的总数,他通常被设置为select监听到所有文件描述符中最大值+1,因为文件描述符总是从0开始计数的。
因为文件描述符是从0开始计数的。
2)readfds、writefds 和 exceptfds 参数分别指向可读、可写和异常等事件对应的文件描述符集合。应用程序调用select函数时,通过这三个参数传入自己感兴趣的文件描述符。select调用返回时, 内核将修改他们来通知应用程序哪些文件描述符已经就绪。
其中fd_set 结构体定义如下

#include <typesizes.h>
#define __FD_SETSIZE 1024

#include <sys/select.h>
#define FD_SETSIZE __FD_SETSIZE
typedef long int __fd_mask;
#undef __NFDBITS
#define __NFDBITS (8 * (int) sizeof(__fd_mask))
typedef struct
{
#ifdef __USE_XOPEN
    __fd_mask fds_bits[__FD_SETSIZE / __NFDBITS];
#define __FDS_BITS(set) ((set)->fds_bits)
#else
    __fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
#define __FDS_BITS(set) ((set)->__fds_bits)
#endif
} fd_set;

其实说白了就是了个
typedef struct
{
int __fds_bits[32];
}fd_set;

所以就相当于fd_set中总共有1024个bit(位), 每一个位标记一个描述符,所以这就是select能同时处理的文件描述符的总量

由于位操作过于繁琐, 我们应该使用下面定义的一系列宏来访问fd_set结构体中的位

#include <sys/select.h>
FD_ZERO( fd_set *fdset ); //清除fd_set中所有位
FD_SET(int fd, fd_set *fdset); //设置fd_set的位fd
FD_CLR(int fd, fd_set *fdset); //清除fdset的位fd
int FD_ISSET(int fd, fd_set *fdset); //测试fd_set的位fd是否被设置

3) timeout 参数用来设置select函数的超时时间,他是一个timeval结构体类型指针, 采用指针参数是因为内核将修改它以告诉应用程序select等待了多久。不过我们不能完全信任select调用返回后的timeout值, 比如调用失败时timeout值是不确定的。timeval结构体定义是这样的

struct timeval
{
    long tv_sec; //秒
    long tv_usec; //微秒
};

如果给timeval每个成员都传0, 则select将立刻返回。如果给timeout传递NULL,selet将一直阻塞,知道某个文件描述符就绪。

返回值
select成功时返回就绪文件描述符的总数。如果在超时时间内设有任何文件描述符就绪,select 将返回0,失败返回-1并设置errno。如果在select等待期间,程序接收到信号,则select立刻返回-1,并设置errno为EINTR。

猜你喜欢

转载自blog.csdn.net/death_include/article/details/66476932