‘壹’ linux下的select函数是干嘛的
不是用得很好吗?精确延时功能。
此外,可以用来判断读写操作是否在指定时间内就绪。
‘贰’ linux下select用法
贴代码来看看
‘叁’ 关于linux select函数fgets函数
操作系统知道文件描述符对应的设备是否可读,所以实际是由内核提供系统调用来真正实现 select 的。
一般对于通过 fopen 操作的文件,我们没必要用 select, 首先你要把 FILE * 转成对应的文件描述符,其次对于标准文件,一般情况下读和写是 non-block 的,select主要是用来对那些会block的设备用的。当然你硬要这么用,也没问题,但是 select 对于这种文件总是会返回可读的,和缓冲区里是否有内容无关(缓冲区的实现是在用户空间的,显然内核不知道其状态)。因为即使整个文件都被读入缓冲区,由于此时描述符处于 EOF 状态, select 仍然会返回可读。
这里实在是有太多细节。 总之,不建议滥用select,对于标准文件或者单个设备的读写,完全没意义。
‘肆’ 关于linux下select函数问题
nfds: 需要检查的文件描述字个数(即检查到fd_set的第几位),数值应该比三组fd_set中所含的最大fd值更大,一般设为三组fd_set中所含的最大fd值加1(如在readset, writeset, exceptset中所含最大的fd为5,则nfds=6,因为fd是从0开始的 )。设这个值是为了提高效率,使函数不必检查fd_set的所有1024位。 否则函数默认会检查到最大值
至于你那个补充内容,是这样的 当调用select()时,由内核根据IO状态修改fe_set的内容,由此来通知执行了select()的进程哪一socket或文件可读写。 这个 是系统内核负责管理的,如果fd1或fd2那个一旦有变化,系统内核会修改其内容就通知select的进程了,如果fd1 fd2都可读 首先肯定有个先后顺序,会记录下来,挨个处理。
‘伍’ Linux中select poll和epoll的区别
select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。
select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内部定义的等待队列)。这也能节省不少的开销。
‘陆’ linux select检测为啥是监听套接字
select系统调用的作用就是让程序在多个文件描述符上进行等待,而套接字也是属于文件描述符的一种,所以服务器程序就可以利用select系统调用,在多个套接字上等待客户端请求,从而达到同时处理多个客户端的效果,而等待客户端请求就需要用listen调用对客户端进行监听,select调用检测的当然就是监听套接字咯。
select系统调用是检测一个已打开的文件描述符的集合(这个集合是一个fd_set类型的数据结构),服务器程序需要创建这个集合,创建时需要用listen调用让套接字处于监听状态,只有这样当有一个新的连接发生时,描述符才会有活动发生,才能够被检测到。
‘柒’ linux select 怎么理解
linux select函数详解
在Linux中,我们可以使用select函数实现I/O端口的复用,传递给 select函数的参数会告诉内核:
•我们所关心的文件描述符
•对每个描述符,我们所关心的状态。(我们是要想从一个文件描述符中读或者写,还是关注一个描述符中是否出现异常)
•我们要等待多长时间。(我们可以等待无限长的时间,等待固定的一段时间,或者根本就不等待)
从 select函数返回后,内核告诉我们一下信息:
•对我们的要求已经做好准备的描述符的个数
•对于三种条件哪些描述符已经做好准备.(读,写,异常)
有了这些返回信息,我们可以调用合适的I/O函数(通常是 read 或 write),并且这些函数不会再阻塞.
#include <sys/select.h>
int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,struct timeval *timeout);
返回:做好准备的文件描述符的个数,超时为0,错误为 -1.
首先我们先看一下最后一个参数。它指明我们要等待的时间:
struct timeval{
long tv_sec; /*秒 */
long tv_usec; /*微秒 */
}
有三种情况:
timeout == NULL 等待无限长的时间。等待可以被一个信号中断。当有一个描述符做好准备或者是捕获到一个信号时函数会返回。如果捕获到一个信号, select函数将返回 -1,并将变量 erro设为 EINTR。
timeout->tv_sec == 0 &&timeout->tv_usec == 0不等待,直接返回。加入描述符集的描述符都会被测试,并且返回满足要求的描述符的个数。这种方法通过轮询,无阻塞地获得了多个文件描述符状态。
timeout->tv_sec !=0 ||timeout->tv_usec!= 0 等待指定的时间。当有描述符符合条件或者超过超时时间的话,函数返回。在超时时间即将用完但又没有描述符合条件的话,返回 0。对于第一种情况,等待也会被信号所中断。
‘捌’ 谁能告诉我 linux下select函数到底是干什么用的 貌似我不用它也可以得到我想要的结果啊
select是用来设置超时时间的,其第一个参数本来是一个文件号,假如读取该文件长时间没有返回则超时跳出,而这部分代码将文件号设置为0,说明只是为了控制延时不过看你这部分代码,明显只是实现一个比较精确定时的sleep这段代码之所以这么做,是因为linux本身的sleep函数非常不准(windows也是一样),在线程较多,cpu任务较重的时候,sleep函数的精确度根本无法达到要求于是你这段代码使用select来代替sleep更为精准,其精准程度和内核相关,如果内核的滴答频率决定的,一般是100HZ也有1000hz的(因内核版本不同而不同),也就是说select做多可以精确到10ms,或者1ms,而sleep就做不到于是这段函数最重要的作用就是用高精确的select函数来代替低精确度的sleep函数,实现时间较为精准的延时。可查阅《Linux就该这么学》了解更多Linux介绍。
‘玖’ Linux内核中select,poll和epoll的区别
select:
下面是select的函数接口:
int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
select 函数监视的文件描述符分3类,分别是writefds、readfds、和exceptfds。调用后select函数会阻塞,直到有描述副就绪(有数据 可读、可写、或者有except),或者超时(timeout指定等待时间,如果立即返回设为null即可),函数返回。当select函数返回后,可以 通过遍历fdset,来找到就绪的描述符。
select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。select的一 个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但 是这样也会造成效率的降低。
poll:
int poll (struct pollfd *fds, unsigned int nfds, int timeout);
不同与select使用三个位图来表示三个fdset的方式,poll使用一个 pollfd的指针实现。
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events to watch */
short revents; /* returned events witnessed */
};
pollfd结构包含了要监视的event和发生的event,不再使用select“参数-值”传递的方式。同时,pollfd并没有最大数量限制(但是数量过大后性能也是会下降)。 和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符。
从上面看,select和poll都需要在返回后,通过遍历文件描述符来获取已经就绪的socket。事实上,同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降。
epoll:
epoll的接口如下:
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
typedef union epoll_data {
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);主要是epoll_create,epoll_ctl和epoll_wait三个函数。epoll_create函数创建epoll文件描述符,参数size并不是限制了epoll所能监听的描述符最大个数,只是对内核初始分配内部数据结构的一个建议。返回是epoll描述符。-1表示创建失败。epoll_ctl 控制对指定描述符fd执行op操作,event是与fd关联的监听事件。op操作有三种:添加EPOLL_CTL_ADD,删除EPOLL_CTL_DEL,修改EPOLL_CTL_MOD。分别添加、删除和修改对fd的监听事件。epoll_wait 等待epfd上的io事件,最多返回maxevents个事件。
在 select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一 个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait() 时便得到通知。
epoll的优点主要是一下几个方面:
1. 监视的描述符数量不受限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左 右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。select的最大缺点就是进程打开的fd是有数量限制的。这对 于连接数量比较大的服务器来说根本不能满足。虽然也可以选择多进程的解决方案( Apache就是这样实现的),不过虽然linux上面创建进程的代价比较小,但仍旧是不可忽视的,加上进程间数据同步远比不上线程间同步的高效,所以也 不是一种完美的方案。
2. IO的效率不会随着监视fd的数量的增长而下降。epoll不同于select和poll轮询的方式,而是通过每个fd定义的回调函数来实现的。只有就绪的fd才会执行回调函数。
3.支持电平触发和边沿触发(只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果我们没有采取行动,那么它将不会再次告知,这种方式称为边缘触发)两种方式,理论上边缘触发的性能要更高一些,但是代码实现相当复杂。
4.mmap加速内核与用户空间的信息传递。epoll是通过内核于用户空间mmap同一块内存,避免了无畏的内存拷贝。
‘拾’ Linux下select函数文件描述符状态的问题
当然是在有输入或者输出时文件描述符的读写状态改变咯,比如标准输入的文件描述符是0,如果用select来等待0号文件描述符,那么当在键盘上敲字符时开始,就是文件描述符的读写状态改变之时,这时select函数就会返回;对于套接字描述符来说也是这样,用select来等待一个服务器描述符,那么当有新的连接请求时(服务器描述符等待请求时是一个读描述符,当有新请求时实际上是有一个输入),服务器描述符的读写状态改变,select函数返回。顺便说一下,检查哪个文件描述符发生改变,可以用FD_ISSET宏来进行检测。