网络IO模型总结
一、阻塞/非阻塞和同步/异步模型
- 阻塞和非阻塞
阻塞指的是调用线程不再执行,一直阻塞在该操作,直到被调方返回结果;而非阻塞是指被调用者会立即返回,但不是运行后的结果,之后可以通过轮训或者被调用者返回信号线、回调函数的方式来提醒调用线程结果。
(1)阻塞是指调用线程由于对方资源被占用等原因,导致无法执行下去;
(2)非阻塞是指调用线程能够正常执行,但结果还未返回,后续再返回数据进行处理
- 同步和异步
(1)同步是指方法调用需要等待返回值,返回结果后才进行下一步操作;
(2)异步是指方法调用不需要等待返回值,直接执行下一步操作,等有结果返回后,再调用回调函数处理。
- 两者区别
(1)阻塞和非阻塞更多说明的是数据从外设复制到内存态缓存区是否会等待,是数据拷贝的过程;同步和异步更多说明的是方法调用是否能够及时返回结果,是数据处理的过程。
(2)阻塞和非阻塞考虑的是线程调用过程资源是否占用情况,同步和异步考虑的是方法调用是否及时返回的情况。
二、Linux中5种常见网络IO模型
说明:IO数据拷贝发生在用户空间获取内核空间的数据过程。
1. 阻塞IO模型
用户空间进程通过系统调用内核空间的IO数据,会一直等待内核空间的数据从内核态拷贝到用户态,拷贝完成才会返回到用户态,造成用户空间的线程一直阻塞。
2. 非阻塞IO模型
用户空间进程通过系统调用内核空间的IO数据,不会一直等待内核空间的数据从内核态拷贝到用户态,每次系统调用都会有个返回值,无论是成功还是失败都会得到响应,用户态的进程没有被阻塞。
3. IO复用模型
对于传统的IO模型,如果存在多个IO连接,则需要创建多个IO接收端,这种情况可以用多线程来实现,但是对于资源会造成很大浪费。基于此创建了IO复用模型,就是由一个select统一轮训IO连接,接受到事件后,将其转接到对应的receiver上去处理。
4. 信号驱动IO模型
信号驱动IO是在IO复用模型上发展起来的,由于IO复用的select是一直轮训,后续将其改造成事件完成后将其信号量通知到客户端,但每次用户空间进程对内核空间的调用都会有返回值。
5. 异步IO模型
异步IO是指用户进程发起系统调用后,内核进程将其数据从内核空间拷贝到用户空间,全程用户进程可以去做其他的时间,等内核进程处理完数据后再通知用户进程。
三、具体实现
1、Socket网络模型
Socket网络模型是一种和平台无关的网络模型。其主要的通信流程如下:
客户端和服务端初始化socket,得到文件描述符;
服务端调用bind,绑定ip和端口;
服务端调用listen,开始进行监听;
服务端调用accept,等待客户端进行连接;
客户端发起connect请求,向服务端发送连接请求;
服务端收到客户端请求后,发送用于传送数据的socket的文件描述符,这样客户端和服务端就建立连接了。
客户端获取文件描述符后,就能够向写文件一下调用write方法向服务端写数据,服务端调用read方法写数据;
客户端数据发送完毕后,调用close方法关闭连接,服务端获取EOF标识符后,就会调用close方法来结束服务器端的操作,两端结束数据的传输。
2、Linux中IO复用的三种实现:select、poll、epoll
select、poll和epoll都是Linux下的IO复用技术,指的是通过一个线程处理多个socket连接;
select是一种轮询机制,由于Linux的连接都是文件状态描述符来保存,select模式会去轮询文件状态描述符来查看状态。该模式的缺点是轮询对象有限,64位的Linux系统也只能是2048个;将已经连接的socket文件描述符放置到bitmap中,再将该bitmap拷贝到内核空间中做检查,看这些socket是在read还是write状态,然后对其进行处理。
poll看起来和select实现的机制差不多,也是通过轮询机制来实现,只是没有了socket连接数量的限制,这是由于他是用链表来保存socket文件描述符。
epoll是基于OS的事件通知机制和回调机制,socket事件发生了会将事件通知到工作线程来处理,同时事件通知保存在红黑树上,所以也没有事件通知的限制;其中epoll有两种触发类型:(1)level类型:只要还有事件没有处理,则会一直通知;(2)edge类型:当有事件过来时,才会进行通知。
3、Java中的NIO
Java的IO模型在服务器端收发数据,会因为没有真正在读写客户端数据而一直阻塞,NIO引入一个Selector,这个线程就是一直轮询客户端的Channel,这个Channel是双向的,既可以读也可以写,同时还引入一个Buffer,就是一个内存区域,读写内容通过Channel先传到这里,之后再被读写操作,因为这个Buffer既能进行读操作、也能进行写操作,所以他通过capacity、limit、position三个指针来表示。 NIO的主要组件如下:
(1)Channel
NIO有多中种Channel实现,在网络通信中用到最多的的SocketChannel,保证非阻塞的通信,就类似于IO中的socket,需要绑定端口号;Channel相比IO的区别是他是一个双工通信的渠道,既可以读,也可以写。
(2)Buffer
Buffer的读写数据:Buffer的数据结构是一块内存区域,他的物理结构是一个数组,其中这个数组有三个重要属性,分别是:capacity、limit、position,他们能分别代表一个Buffer的容量、能够操作的上限、当前位置信息。其中ByteBuffer最常见,他的物理结构是一个byte数组。其中常见方法有allocate(),这个创建byteBuffer,还有读写方法;
(3)Selector
Selector的作用是轮询IO信道,简单来说就是不断轮训注册在他上面的Channel,监听他的连接、读写操作,如果有这些操作,就返回一个Selectkey值,通过这个值就能找到那个Channel;
(4)总结
其中Channel对应以前的流,Buffer也不是什么新东西,就是一个内存区域,Selector是因为NIO可以使用异步的非堵塞模式才加入的东西。
基于NIO实现的服务器模型
四、网络通信模型
1、Reactor网络模型
Reactor网络模型就是利用IO多路复用方式监听事件,selector收到事件后利用dispatcher分发事件到对应的处理线程,其中Acceptor用以处理连接事件,Handler用以处理具体业务。
其中Reactor网络模型分为单Reactor单线程模型、单Reactor多线程模型、主从Reactor多线程模型,其中单Reactor单线程模型示意图如下,只有一个Reactor,Handler也是单线程来处理;单Reactor多线程模型只有一个Reactor,但通过多线程的Handler来处理业务;主从Reactor多线程模型有主从两个Reactor,通过多线程的Handler来处理业务。