什么是多路复用
很多地方都说到这个名词?其实没那么难理解,其实是一个操作系统的概念,是一种监听的机制,操作系统负责监听多个文件描述符(soket其实在linux就是一个文件,或者缓存区);区别:端口和socket是两个不同的东西,socket可以理解为一个文件或者缓存区。
阻塞和非组赛
也没那么难理解,和操作系统课本的概念是一样的,都是说进程或者线程的一种状态,并不是说用了NIO非阻塞类型的编程就不存在阻塞了,当没有任何客户端发信息到socket就是阻塞的,
BIO和NIO
BIO就是一个线程(入门教程说的是主线程)负责一个客户端完bind(绑定端口号进行监听) ,accept(会返回一个连接成功的socket),read(),write(),走完一个客户端的流程再去处理其他的客户,但是这个过程会涉及到很多问题,没有客户端发起连接时该进程会一直阻塞在哪里,连接成功了但是没有发信息也会阻塞在哪里等待socket被写入信息,BIO模式下是新建了一个while(true)一个个处理socket的,效率很慢,
NIO实现思路:新建一个socket的list来存储监听端口上的socket,每一个心的用户发起连接就产生一个新的socket望这个list加,这种list的实现类有selector,poll,epoll三种比较典型,epoll是现在最强的。NIO的设计思路会新让每一步(bind,accept,read,write),都交给相应的线程(线程池)来执行,不会像BIO那样在主线程那里新建一个while循环一个用户一个用户的处理。有了这些线程处理了,但是问题来了,有很长一段时间没有用户来连接,有些socket很长一段时间没有发来信息即socket是空的,这些线程会一直在哪里执行占用cpu资源吗?应该让他们阻塞,释放cpu资源,当有用户要连接,socket有信息的时候才运行起来。但是谁来唤醒他们的呢?操作系统来,把这些监听是不是有新的socket连接,socket是不是空的,缓存区是不是空的(满的)工作的交给操作系统,当有事件时就唤醒相应的应用线程(selector,poll,epll)来干活。这就是多路复用。。java里面的NIO包下的很多实现都是通过调用本地方法native方法通过c语言的方法实现的,c语言方法下通过操作系统的系统调用实现的。例如java的Socketchanel就是调用了native方法。。
select poll 和epoll区别
在没有三者之前,多路复用是非阻塞不断地轮询socket集合的,就是说socket有没有信息写入都是不断地轮询访问,效果可想而知是非常浪费cpu资源的,通过select,poll和epoll来实现的多路复用只有在socket有数据写入才会唤醒线程来处理。在空闲的时候,把当前处理线程阻塞掉,当有一个或多个描述符/流就绪的时候,就从阻塞状态中醒来进行处理。三者是不断升级的过程,epoll最好。
三者区别主要从他们三个是如何存储socket集合,如何遍历处理队列socket的两个方面来比较。select工作机制中,在知道有文件描述符就绪就唤醒处理线程处理socket的list集合,但具体是哪一个socket就绪,socke就是一个文件或者一个缓冲区。从开始开始轮询,当很多个连接的时候select这种机制的性能就会急剧下降,遍历过程花费太多时间,例如只有一个socket发来了信息你去遍历了整个长长的list很浪费时间的。这就是select的弊端,并且有socket连接数量的上限。
poll和select的区别就是没有socket连接数量的上限限制,因为这个是链式存储的list,基本机制和select的差不多
Epoll最大的优点就在于它只管你“活跃”的sockket,而跟socke总数无关,这就让处理线程不用丛头开始遍历
三者区别参考参考
手写BIO NIO AIO
手写BIO参考
手写NIO
AIO