Molet

在Linux环境下select函数的初体验

Molet 运维技术 2022-11-20 629浏览 0

在Linux环境下select函数的初体验

select介绍

在linux中, 主要的 IO复用方式中, 有epoll, poll 和select, 这次先来学习下select.

select 能够同时监视多个文件描述符的变法, 也支持超时返回.

先来看下select函数的定义

/*/usr/include/sys/select.h*/
externintselect(int__nfds,//最大文件描述符+1
fd_set*__restrict__readfds,//读状态文件集
fd_set*__restrict__writefds,//写状态文件集
fd_set*__restrict__exceptfds,//异常状态文件集
structtimeval*__restrict__timeout);//超时时间

如上图函数声明所示, 不管我们关注什么状态, 我们都应该把同一类状态的文件描述符存到同一个fd_set集合,以便select能够相应的位置打上标签, 以便后续我们来判断该文件描述符是否已经准备好

这些传递给select函数的参数, 将告诉内核:

  • 我们需要监听的文件描述符
  • 对于每个文件描述符, 我们所关心的状态 (读/写/异常)
  • 我们要等待多长时间 (无限长/超时返回)

而内核也会通过select的返回, 告知我们一些信息:

  • 已经准备好的文件描述符个数
  • 那三种状态分别是哪些文件描述符

我们可以通过以下方式将关注的文件描述符加入相应的文件集:

intsocket_test;
socket_test=socket(...);//创建socket文件描述符
connent(socket_test,..);//连接服务端
FD_SET(socket_test,&rdfds);//加入读状态文件集
FD_SET(socket_test,&wdfds);//加入写状态文件集
....

select原理

select函数执行顺序是: SYSCALL_DEFINE5 (sys_select) -> core_sys_select -> do_select

我们都知道, select 支持监听三个文件集: 读文件集, 写文件集, 异常文件集;

在我们调用FD_SET(socket_test, &rdfds)时, 实际上执行的操作是: 在rdfds成员数组中, 将__FDELT (d)位置的值 设成 __FDMASK (d), 直接说会有点疑惑, 先看下相关的函数,宏定义是怎样定义的吧:

/*取自:/usr/include/sys/select.h*/
#defineFD_SET(fd,fdsetp)__FD_SET(fd,fdsetp)
typedeflongint__fd_mask;

/*取自:/usr/include/bits/select.h*/

#define__NFDBITS(8*(int)sizeof(__fd_mask))
#define__FDELT(d)((d)/__NFDBITS)
#define__FDMASK(d)((__fd_mask)1<<((d)%__NFDBITS))

#define__FD_SET(d,set)(__FDS_BITS(set)[__FDELT(d)]|=__FDMASK(d))

typedefstruct
{
/*XPG4.2requiresthismembername.Otherwiseavoidthename
fromtheglobalnamespace.*/
#ifdef__USE_XOPEN
__fd_maskfds_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;

/*/usr/include/linux/posix_types.h*/
#define__FD_SETSIZE1024

举个栗子, 假设 fd=3, 当我们执行FD_SET(fd, &rdfds)时:

  1. 算出 __FDELT(d) 和 __FDMASK(d)的值,

继续浏览有关 Linux 的文章
发表评论