linux网络编程之select poll epoll对比整理

IO复用:

因为在linux中,一切皆文件,而文件就是一串二进制流。IO操作即是对文件进行读写(系统调用read/write)。

同步和异步针对应用程序来说,关注的是程序中间的协作关系;阻塞与非阻塞更关注的是单个进程的执行状态。

同步有阻塞和非阻塞之分,阻塞、非阻塞、多路IO复用,都是同步IO;异步必定是非阻塞的。

同步:执行一个操作之后,进程触发IO操作并等待(也就是我们说的阻塞)或者轮询的去查看IO操作(也就是我们说的非阻塞)是否完成,等待结果,然后才继续执行后续的操作。

异步:执行一个操作后,可以去执行其他的操作,然后等待通知再回来执行刚才没执行完的操作。

阻塞:进程给CPU传达一个任务之后,一直等待CPU处理完成,然后才执行后面的操作。——阻塞忙等

非阻塞:进程给CPU传达任务后,继续处理后续的操作,隔断时间再来询问之前的操作是否完成。这样的过程其实也叫轮询。——非阻塞忙

异步IO即是用户线程需要IO操作时,线程不等待CPU的IO结果(IO的执行由CPU完成),直接返回继续执行下面的操作,等待一个IO完成的信号后,再处理数据。也就是select、poll、epoll都是同步IO。

一、select

1、select简述

select是网络IO模型中的IO复用。

select使用描述字集,典型地是一个整数数组,其中每个整数中的每一位对应一个文件描述字。

select的问题:

select 中由于FD_SETSIZE设置,默认值是1024,所以对于那些需要支持的上万连接数目服务器来说显然太少了。而且即使选择修改这个宏然后重新编译内核,有资料也指出这样会带来网络效率下降。

另外,在内核中的select实现中,select是采用无差别轮询来处理的,即每次检测都会遍历所有fd_set中的句柄,所以select具有O(n)的无差别轮询复杂度,同时处理的流(fd)越多,无差别轮询时间就越长。


3、函数原型

#include  
int select (int maxfd+1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval * timeout);

struct fd_set可以理解为一个集合,这个集合中存放的是文件描述符(filedescriptor),即文件句柄。

fd_set集合可以通过一些宏由人为来操作,比如:

清空集合FD_ZERO(fd_set*);

将一个给定的文件描述符加入集合之中,FD_SET(int,fd_set*);

将一个给定的文件描述符从集合中删除,FD_CLR(int, fd_set*);

检查集合中指定的文件描述符是否可以读写,FD_ISSET(int,fd_set*)

参数解释

参数一:是指集合中所有文件描述符的范围,且文件描述符的最大值加1。

参数二:用于检查可读性,是否可以读了,如果这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件可读,如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的读变化。

参数三:用于检查可写性,是否可以写了,如果这个集合中有一个文件可写,select就会返回一个大于0的值,表示有文件可写,如果没有可写的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的写变化。

参数四:用于检查带外数据,用来监视文件错误异常。

参数五:一个指向timeval结构的指针,用于决定select等待I/o的最长时间,如果为空将一直等待。

timeval结构的定义:

struct timeval{
long tv_sec; // seconds
long tv_usec; // microseconds
}

返回值

>0:就绪描述字的正数目

-1:出错

0 :超时

二、poll

1、poll简述

select,poll的实现功能差不多,但poll效率更高。


2、函数原型

unsigned int (*poll)(struct file * fp, struct poll_table_struct * table)
#include 
int poll(struct pollfd fds[], nfds_t nfds, int timeout);

struct pollfd的结构:

struct pollfd {
int fd;        /*文件描述符*/
short events;  /* 等待的需要测试事件 */
short revents; /* 实际发生了的事件,也就是返回结果 */
};
当返回正值时,代表满足响应事件的文件描述符的个数,如果返回0则代表在规定时间内没有事件发生。如发现返回为负则应该立即查看 errno,因为这代表有错误发生。

三、epoll

1、epoll简述

selectepoll大的好处在于它不会随着监听fd目的增而降低效率。

epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll会把哪个流发生了怎样的I/O事件通知我们。所以我们说epoll实际上是事件驱动(每个事件关联上fd的,对这些流操作的复杂度降低到了O(1)。

所以,selectepoll最大的区别就是:select只是告诉你一定数目的流有事件了,至于哪个流有事件,还得你一个一个地去轮询,而epoll会把发生的事件告诉你,通过发生的事件,就自然而然定位到哪个流了。epollselect相比,也是一种牺牲空间,换取时间的思想

epoll的两种工作模式:

(1)、ET模式——Edge Triggered边沿触发

ET模式仅当状态发生变化的时候才能获得通知,这⾥所谓的状态的变化并不包括缓冲区中还有未处理的数据,也就

是说,ET模式需要一直read/write直到出错为止。

ET是高速工作方式,只支持no-block socket。

(2)、LT模式——Level Triggered水平触发

LT模式是缺省的工作方式,并且同时支持block和no-block socket。

LT模式是只要数据没有处理就会一直通知下去,相较于ET模式,LT模式编程出错的概率可能性要小一点。

而select/poll都是LT模式典型代表。


参考链接:

https://baike.so.com/doc/5398007-5635387.html

https://www.cnblogs.com/aspirant/p/6877350.html

https://blog.csdn.net/sxtobj/article/details/53158016

你可能感兴趣的:(linux系列,linux之网络编程)