linux高并发模型

1、unix体系结构在这里插入图片描述

内核:即操作系统内核,用户控制计算机硬件。
系统调用:内核的接口被称为系统调用(由操作系统实现并提供给外部应用程序的编程接口,是应用程序同系统之间数据交互的桥梁)
公共库函数:公用库函数构建在系统调用接口之上,应用程序即可使用公共函数库,也可使用系统调用。
shell:shell是一个特殊的应用程序,为运行其他程序提供了一个接口。

2 I/O模型

2.1 阻塞I/0

阻塞 I/O 是最简单的 I/O 模型,一般表现为进程或线程等待某个条件,如果条件不满足,则一直等下去。条件满足,则进行下一步操作。相关示意图如下:
在这里插入图片描述

2.2 非阻塞I/0模型

与阻塞 I/O 模型相反,在非阻塞 I/O 模型下。应用进程与内核交互,目的未达到时,不再一味的等着,而是直接返回。然后通过轮询的方式,不停的去问内核数据准备好没。示意图如下:
在这里插入图片描述
上图中,应用进程通过 recvfrom 系统调用不停的去和内核交互,直到内核准备好数据报。从上面的流程中可以看出,应用进程进入轮询状态时等同于阻塞,所以非阻塞的 I/O 似乎并没有提高进程工作效率。

2.3 I/O 复用模型

Unix/Linux 环境下的 I/O 复用模型包含三组系统调用,分别是 select、poll 和 epoll(FreeBSD 中则为 kqueue)。select 出现的时间最早,在 BSD 4.2中被引入。poll 则是在 AT&T System V UNIX 版本中被引入(详情请参考 UNIX man-page)。epoll 出现在 Linux kernel 2.5.44 版本中,与之对应的 kqueue 调用则出现在 FreeBSD 4.1,早于 epoll。select 和 poll 出现的时间比较早,在当时也是比较先进的 I/O 模型了,满足了当时的需求。不过随着因特网用户的增长,C10K 问题出现。select 和 poll 已经不能满足需求了,研发更加高效的 I/O 模型迫在眉睫。到了 2000 年,FreeBSD 率先发布了 select、poll 的改进版 kqueue。Linux 平台则在 2002 年 2.5.44 中发布了 epoll。好了,关于三者的一些历史就说到这里。本节接下来将以 select 函数为例,简述该函数的使用过程。
select 有三个文件描述符集(readfds),分别是可读文件描述符集(writefds)、可写文件描述符集和异常文件描述符集(exceptfds)。应用程序可将某个 socket (文件描述符)设置到感兴趣的文件描述符集中,并调用 select 等待所感兴趣的事件发生。比如某个 socket 处于可读状态了,此时应用进程就可调用 recvfrom 函数把数据从内核空间拷贝到进程空间内,无需再等待内核准备数据了。示意图如下:
在这里插入图片描述
一般情况下,应用进程会将多个 socket 设置到感兴趣的文件描述符集中,并调用 select 等待所关注的事件(比如可读、可写)处于就绪状态。当某些 socket 处于就绪状态后**,select 返回处于就绪状态的 sockct 数量。注意这里返回的是 socket 的数量,并不是具体的 socket**。应用程序需要自己去确定哪些 socket 处于就绪状态了,确定之后即可进行后续操作。

c10k问题

epoll的API详解
在这里插入图片描述

  1. int epoll_create(int size)

epoll与select、poll的对比

1 用户态将文件描述符传入内核的方式
select:创建3个文件描述符集并拷贝到内核中,分别监听读、写、异常动作。这里受到单个进程可以打开的fd数量限制,默认是1024。
poll:将传入的struct pollfd结构体数组拷贝到内核中进行监听。
epoll:执行epoll_create会在内核的高速cache区中建立一颗红黑树以及就绪链表(该链表存储已经就绪的文件描述符)。接着用户执行的epoll_ctl函数添加文件描述符会在红黑树上增加相应的结点。

2 内核态检测文件描述符读写状态的方式
select:采用轮询方式,遍历所有fd,最后返回一个描述符读写操作是否就绪的mask掩码,根据这个掩码给fd_set赋值。
poll:同样采用轮询方式,查询每个fd的状态,如果就绪则在等待队列中加入一项并继续遍历。
epoll:采用回调机制。在执行epoll_ctl的add操作时,不仅将文件描述符放到红黑树上,而且也注册了回调函数,内核在检测到某文件描述符可读/可写时会调用回调函数,该回调函数将文件描述符放在就绪链表中。
3、

找到就绪的文件描述符并传递给用户态的方式

select:将之前传入的fd_set拷贝传出到用户态并返回就绪的文件描述符总数。用户态并不知道是哪些文件描述符处于就绪态,需要遍历来判断。
poll:将之前传入的fd数组拷贝传出用户态并返回就绪的文件描述符总数。用户态并不知道是哪些文件描述符处于就绪态,需要遍历来判断。
epoll:epoll_wait只用观察就绪链表中有无数据即可,最后将链表的数据返回给数组并返回就绪的数量。内核将就绪的文件描述符放在传入的数组中,所以只用遍历依次处理即可。这里返回的文件描述符是通过mmap让内核和用户空间共享同一块内存实现传递的,减少了不必要的拷贝。
4、重复监听的处理方式
select:将新的监听文件描述符集合拷贝传入内核中,继续以上步骤。
poll:将新的struct pollfd结构体数组拷贝传入内核中,继续以上步骤。
epoll:无需重新构建红黑树,直接沿用已存在的即可。

1.多进程并发模型

核心思想:一个服务器和多个客户端进行通信,每来一个客户端进行连接就创建一个进程,将接收到的文件描述符给对应的子进程,形成一对一的访问机制。当一个客户端关闭的时候,就退出子进程。
在这个过程中父进程扮演的角色是?

  • 等待接受客户端的连接
  • 有连接就创建一个子进程
  • 将通信的文件描述符关闭

子进程扮演的角色?

  • 进行与客户端的通信
  • 关闭监听的文件描述符(减少资源的开销)

缺点:
a:启动和关闭进程带来开销
b:系统最多只能创建512个进程,文件描述符默认的限制也是1024,无法形成大规模的访问

2多线程并发模型

核心思想:
每有一个客户端连接,就创建一个子线程,通过回调函数函数进行业务的处理,并将文件描述符传给创建的线程。因为每一个线程都需要一份独立的数据
缺点:多线程存在线程创建的开销,而且如果大量的用户访问还存在线程切换的问题

3多路I/0转接服务器

核心思想:
不再由应用程序自己监听客户端的连接,取而代之由内核替应用程序监视文件
主要有select()/poll()/epoll()这三种方法
3.1 select()
核心思想:
创建文件描述符集合,调用select()函数完成内核检测有多少个文件描述符发生变化,函数的返回值是有多少个文件描述符发生变化
优点:跨平台
缺点:

  • 每次调用select()函数都需要把fd集合把用户态拷贝到内核态这个开销会很大
  • 需要线性遍历文件描述符数组,随着fd的增加效率会显著的下降

3.2poll()
poll的方法和select()一样只是将select中的读集合、写集合、出错集合、封装成结构体中的事件
3.3epoll()(最高效)
核心思想:不仅能够返回有多少个文件描述符发生变化,而且还能返回这些变化的文件描述符时哪些。
epolll效率高效的原因在于数据结构的设计

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 */
};

epoll_data保留了fd利用它直接可以定位客户端的文件描述符
epoll_wait()的核心理解
1 返回就绪事件的个数
2 将就绪客户端的信息保存到event数组中,将所以的就绪事件从内核事件表中复制到events指向的数组中

epoll的三种工作方式

1水平触发方式
只用fd对应的缓冲区中有数据epoll_wait()就返回
返回的次数与发送的次数无关
epoll默认的工作方式
2边缘触发方式
不管数据有没有读完,只有客户端发送数据的时候,才触发,通过把缓冲区的数据挤出来的方式,发出数据的
3边缘非阻塞方式
这是最好的方法
核心思想:
把缓冲区中的数据全部读完,通过改变文件描述符的默认属性,将其设置为非阻塞的方式来进行实现的
https://www.jianshu.com/p/31cdfd6f5a48

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值