编程语言
首页 > 编程语言> > 网络编程模式

网络编程模式

作者:互联网

引入

​ 服务器处理客户端请求,最直接的方式就是一对一即一个请求创建对应的线程或进程。(其中创建线程优于创建进程,线程的上下文切换较进程切换轻便,线程通信也要比进程通信简单)但这种方式是阻塞式的,也就是说若线程遇到无数据可读会阻塞当前线程,造成资源浪费。在高并发当道的今天,这种方式也是不可能的,不可能一万请求就创建一万线程。

​ 进而考虑能否让请求资源准备好后再发起请求,实现这一技术的就是IO多路复用。IO多路复用会使用系统调用函数监听我们期望的连接,线程可以通过函数从内核中获取事件。获取事件时,先将连接传递给内核,由内核检测:没事件发生,线程阻塞该函数。有事件发生,内核返回事件的连接,线程从阻塞状态返回,进而用户态来处理对应的业务。这其中涉及到内核态,用户态的知识。IO多路复用接口写网络程序是面向过程写代码,效率较低。

Reactor

​ 大佬基于面向对象的思想封装了IO多路复用,并起了名字叫 Reactor模式。Reactor翻译为响应器,意为对事件的响应,也就是说有事件发生的话,Reactor会有响应的反应。别名Dispatcher模式,即IO多路复用监听事件,根据收到的事件类型分配给某进程/线程。

​ Reactor模式由Reactor和处理池两核心部分组成:Reactor负责监听和分发事件,如连接事件、读写事件;处理池负责处理事件,如read-> 业务 -> send;Reactor可以有多个,处理资源池也一样,可以是单线/进程,或多线/进程。两两组合有四中方案:单Reactor单程、单Reactor多程、多Reactor单程、多Reactor多程,其中单Reactor单程较多Reactor多程简单省事,且性能一致,所以后者被pass了,故余下3个有实际应用:单Reactor单程、单Reactor多程、多Reactor多程。具体用进程还是线程看具体环境:Java语言一般用线程,如Netty;C语言进程线程都可以,如Nginx用进程、Memcache用线程

​ C语言实现单Reactor单进程、Java实现单Reactor单线程

单Reactor单程

202205021626

构成

说明

总结:单Reactor单程的方案因为工作都在同进程内完成,实现较为简单,不用考虑进程通信和多线程竞争。但优于单进程无法利用多核cpu性能,且handler处理期间,整个进程无法处理其他连接事件,若业务较慢会造成响应慢。

应用:单Reactor单程不适于计算密集的场景,只适用于业务处理非常快的场景。Redis由C实现,采用的正式单Reactor单程模式,Redis业务处理主要在内存中,速度快且性能瓶颈不在cpu。

单Reactor多程

202205021647

说明

总结

多Reactor多程

202205021702

说明

总结

Proactor

​ Reactor是同步非阻塞网络,Proactor是异步非阻塞网络

阻塞IO:当用户执行read,线程阻塞,一直到内核数据准备好,并将数据从内存缓冲区拷贝到应用程序的缓冲区,当拷贝完成完成,read才会返回。这里等待的是两个过程:1)内核数据准备。2)数据从内存缓冲区拷贝到应用程序缓冲区

Ok9SFU.png

非阻塞IO:非阻塞IO的read请求在数据未准备好时,线程不再等待,往下继续执行,但程序会不断轮训内核,直到数据就绪,内核将数据拷贝到应用程序缓冲区,read调用才获取结果。注意:这里的第二次等待是不可避免的即将数据拷贝至程序缓冲区

123

​ 最后一次调用,指数据从内核缓冲区拷贝到程序缓冲区这个过程,是同步的。无论read、send的阻塞IO还是非阻塞IO这一步都不可避免 ,若内核的拷贝效率不高,read调用会在该过程阻塞较长事件。真正的异步IO是这两步都不用等待,即内核数据就绪、内核缓冲区拷贝到用户程序缓冲区都不需要等待。当发起aio_read(异步IO)后,立即返回,内核自动将数据从内核空间拷贝到用户空间,这个过程是异步的,内核自动完成,与前面的同步操作不同,应用程序并不需要主动拷贝。我理解是内核的限制被放开了,原来可能由于数据拷贝的问题导致内核不能有效利用,改成异步效率高

OkogC6.png

模式图

工作流程

​ linux下异步IO是不完善的,aio系列函数由POSIX定义的异步操作接口,不是系统级别支持,仅为用户空间模拟的异步,且仅支持本地文件的AIO异步操作,网络编程中socket是不支持的,使基于linux的高性能网络程序都用Reactor方案,windows实现完整的支持socket的异步编程接口IOCP,系统级别的实现异步IO,因此windows内实现的高性能网络程序可以使用更高效的proactor方案

总结

​ Reactor是同步非阻塞网络模式,感知的是就绪可读写事件。每次感知到有事件发生(如读写事件),要程序进程调用read方法完成数据读取,也就是要应用进程主动将socket接受缓存中的数据读到应用程序内,该过程是同步的,读完后应用进程才能处理数据

​ Proactor是异步非阻塞网络模式,感知的是已完成读写事件。发起异步读写请求时,要传入数据缓冲区地址(保存数据)等信息,然后系统内核会自动将数据的读写工作完成,不需要像Reactor那样要程序主动read、write来读写,内核完成后会通知应用程序直接处理数据的。

​ Reactor是事件来了系统通知程序来处理;Proactor是事件有系统处理,好了告诉程序。

​ 这里的事件有:新链接、数据可读、数据可写

​ 这里的处理有:从驱动读取到内核、从内核读取到用户空间

Reactor的实现方案

Proactor是最猛的,异步IO实现网络模型,感知已完成事件,但linux没有实现

参考文章

如何深刻理解Reactor和Proactor?

标签:Reactor,编程,网络,模式,handler,线程,内核,IO,事件
来源: https://www.cnblogs.com/lifelikeplay/p/16221868.html