select,poll,epoll的c++实现

1. select,poll,epoll的区别

  linux作为一个完整的系统,从系统层面上就支持3种创建TCP Serve的方式,分别是select,poll和最新epoll。不管是linux系统还是windows系统,都实现了select和poll,对于epoll,只有linux系统实现了该功能,windows有类似的功能 IOCP。
  select是最古老的一种IO模型,它的特点是在用于TCP服务器时,将socket的文件描述符放在一个数组(fd_set)中,然后每次调用select()函数时,内核都会对每一个socket链接进行检查,查看是否有事件发生。这种方式有以下的两个缺点:

  1. 存放socket文件描述符的数组的大小是固定长度的,也就意味着,这个数组从申请之后,长度就是固定了,一旦socket链接过多,超过数组的长度,那么该数组必然会越界访问,造成异常。当然有些人可能会说,能不能申请一个非常大的数组,这样就不怕溢出。可是该数组的大小是受到操作系统的限制的,并不是任意申请大小的,linux下,该数组的大小固定为1024。
  2. 大小固定的数组,会造成空间资源的浪费,因为很多时候,我们的TCP服务器并没有那么多的链接。比如我们只有10个链接,那么该数组剩下的1014的位置都是已经在内存中占用,但是我们却不会使用到。

  poll是select的改进模型,poll将原来存放socket文件描述符的数组改进变为了链表,链表解决了链接数量上限问题,但是select和poll仍然会面临一个问题:系统会对每一个socket进行无差别的轮询,时间复杂度为O(N),随着链接数的增加,系统轮询所需的时间越来越大。
  epoll是select,poll的改进模型,epoll的优点如下:

  1. epoll理论没有链接数的上限,实际上epoll的链接数上限与系统的文件描述符的上限有关,正常的linux系统默认的文件描述符上限为约10万个,可以通过命令cat /proc/sys/fs/file-max来查看。
  2. epoll内部有等待队列,当设备触发相关事件时,系统会把设备的文件描述符加入到内部的就绪列表,程序每次去获取就绪列表即可知道哪些socket触发了响应的事件。这种方式下,N个链接与1个链接对程序获取触发事件的socket的时间消耗是差不多的,所以epoll会比select和poll更加的高效。

2. select,poll,epoll的实现

gitee地址: https://gitee.com/evilskyman/socket-test
下载好后,使用下列命令可以启动程序

cd socket-test && cd build
cmake ..
make
./../bin/socketTest

此时程序会启动3个TCP服务器,分别是select,poll,epoll三种模型的TCP服务器。端口是在源文件里面定义的,分别是

#define pollPort 8080
#define selectPort 9970
#define epollPort 9980

3. 具体细节

具体的实现方法可以看代码。比较关键的细节如下:

  1. select的关键在于维护 fd_set 这个数组,新增加的 client_fd 也必须加入到 fd_set ,需要注意的是,fd 文件描述符是非负数,由系统分配,默认是后一个fd是前一个fd+1,负数的fd是无效的。调用select()函数后,fd_set 会保存对应标志位,然后使用FD_ISSET()函数即可判断对应的socket是否有消息。
  2. poll的关键在于维护pollfd,poll在增加新的监听socket时,是可以指定监听的事件的,调用poll()函数以后,根据对应事件的标志位,即可判断是否有事件发生。poll新增socket,在于将socket的文件描述符Fd加入到pollEvent中,EventNum也要加一,然后在下一次调用poll()时,poll()会根据输入参数的变化,对新的socket进行监听。
  3. epoll的使用需要使用epoll_create()函数创建一个实例的,这和select,poll是不一样的。epoll内部也会保存需要监听的socket的fd,但是是隐形的管理,对于用户来说是间接管理,用户需要使用epoll_ctl()函数去管理epoll里面的socket。对于epoll来说,每次调用epoll_wait(),epoll都会返回发生的事件数,然后根据事件里面的fd,就可以知道是哪个socket触发了事件。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值