网络编程模型(I/O模型)

Posted 128-cdy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络编程模型(I/O模型)相关的知识,希望对你有一定的参考价值。

首先了解什么是同步(synchronous),异步(asynchronous),阻塞(blocking),非阻塞(nonblocking):

同步与异步

同步和异步是基于应用程序与操作系统处理I/O所采用的方式

同步:是应用程序直接参与I/O读写的操作,么有完毕将会等待(当应用程序发起read操作,如果内核缓冲区无该数据,则一直等待,直到内核缓冲区数据完成,在该阶段应用程序不能进行其他事情)

异步:所有的I/O读写操作都交给操作系统处理,应用程序只需要等待通知(当应用程序发起read操作,交由操作系统完成,在该阶段应用程序能执行其他业务,但需要不定时查询内核缓冲区数据是否完成)

阻塞和非阻塞

阻塞和非阻塞是进程在访问数据的时候,数据是否准备就绪的一种处理方式

阻塞:需要等待缓冲区的数据准备好后才能处理其他的事情,否则一直等待在这里(内核缓冲区到本地数据读取数据,如果本地数据么有准备好,则该请求线程一直等待,直到获取数据返回到缓冲区)

非阻塞:当进程访问数据缓冲区时,如果数据没有准备好则直接返回,不会等待,返回相应的状态码。如果数据已经准备好了,直接返回(内核缓冲区读取本地数据,本地数据不管是否准备好,都立即返回)

 

技术图片

I/O模型:同步非阻塞(NIO)/同步阻塞(BIO)/异步阻塞/异步非阻塞(AIO)

 

操作系统常见的I/O模型

  • 阻塞I/O模型

      在用户线程发出I/O请求后,内核会检查数据是否就绪,此时用户线程会一直阻塞等待数据内存就绪,在内存数据就绪后,内核将数据复制到用户线程中,并返回I/O执行结果到用户线程,此时用户线程将解除阻塞状态并开始处理数据。

  • 非阻塞I/O模型

       用户线程在发起一个I/O操作,无需阻塞便可以马上得到内核返回的结果。如果内核的返回结果为false,则表示内核数据未准备好,需要稍后再次发起I/O请求。一旦内核中数据准备好,并且再次收到用户线程的请求,内核就会立刻将数据复制到用户线程并将复制到的结果通知用户线程。

  • 多路复用I/O 模型

       是多线程并发编程用的较多的模型,通过在一个Selector线程上以轮训方式检测在多个Socket上是否有多个事件到达,并逐个进行事件处理和响应。因此,对于多路复用I/O,在事件的消息体很大时,Selector线程就会成为性能瓶颈,导致后续的事件迟迟的得不到响应,影响下一轮的事件轮询。在实际应用中多路复用建议只做数据的接收和转发,将具体的业务操作以及复杂的逻辑运算转发给后面的业务线程处理。

  • 信号驱动I/O模型

      用户线程发起一个I/O请求,系统会为该请求对应的Socket注册一个信号函数,然后用户线程可以继续执行其他业务逻辑,在内核数据就绪时,系统发送一个信号到用户线程,用户线程在收到信号后,会在信号函数中调用对应的I/O读写操作来完成实际的I/O请求操作。

  • 异步I/O模型

      在该模型中,用户线程会发起一个Asynchronous read操作到内核,内核在接收到Asynchronous read请求后会立即返回一个状态,来说明此时的请求是否成功发起,在这个过程中用户线程不会发生任何的阻塞;接着内核会等待数据准备完成并将数据复制到用户线程中,复制完后内核发送一个信号到用户线程,通知用户Asynchronous操作完成。在该模型下,用户线程不需要关心整个的I/O操作如何进行,只需要发起一个请求,直接使用数据即可。

Java中的I/O模型

  • BIO  同步阻塞模型 (JDK1.4前使用)

      需要先在服务端启动一个ServerSocket,然后客户端启动一个Socket来对服务端进行连接,默认情况下服务端需要对每一个请求建立一个线程,客户端发送请求后,需要等待服务端是否有相应的线程来处理客户端的连接,如果么有线程则一直等待或者拒绝请求,如果有则等待线程处理客户端的请求。

  • NIO  同步非阻塞模型 (JDK1.5后提供)

       主要涉及三大核心内容:(选择器)Selector、(通道)Channel、(缓冲区)Buffer。Selector用于监听多个Channel的事件,一个线程可以实现对多个数据的Channel的管理。他是基于Channel和Buffer进行I/O的读写操作,数据总是被从Channel读取到Buffer,或者从Buffer写入到Channel。

       Channel:用于IO操作的连接,在Java.nio.channels包下定义的,对原有IO的一种补充,不能直接访问数据需要和缓冲区Buffer进行交互,Channel是双向的,既可以用来进行读操作,也可用来进行写操作。

      通道主要实现类:

      SocketChannel:通过TCP读写网络中的数据,一般用于客户端的实现。

      ServerSocketChannel:监听新进来的TCP连接,对每一个连接都需要创建一个SocketChannel,一般用于服务端的实现。

       Buffer:一个容器,内部通过一个连续的字节数组存储I/O上的数据,NIO中,Channel的文件,网络上对数据的读取或者写入都必须经过Buffer。

       技术图片

       Selector:用于检测在多个注册的Channel上是否有I/O事件发生,并对其进行响应和处理。可以通过一个Selector线程就可以实现对多个Channel的管理,不必为每一个连接创建一个线程,避免了线程资源的浪费和线程间上下文切换的开销;只有在Channel上有读写事件时,才会调用I/O进行读写操作,极大地减少系统开销,提高系统并发量。

      传统I/O与Java NIO的区别:

     (1)传统的I/O操作是面向流的,数据只能在一个流中进行连续的读写,数据无缓冲,字节流无法前后移动;而NIO是面向缓冲区的的,可以方便的在缓冲区中进行数据的前后移动等操作,该功能在应用层主要用于数据包的重组、粘包、拆包等操作,在网络不可靠的环境下尤为重要。

     (2)传统的I/O模型是阻塞模式的,在用户线程调用read()或者write()操作时,该线程将会一直被阻塞,直到读或者写操作完成;NIO通过Selector监听Channel上的事件的变化,在Channel上有数据发生变化时通知该线程进行读写操作。对于读请求,在通道上有可用的数据时,线程将进行Buffer的读操作,再无数据时,线程可执行其他业务逻辑;对于写操作,一个线程执行写操作将一些数据犹如通道时,只需要将Channel上的数据异步的写入到Buffer,Buffer上的数据异步写入到Channel即可,用户线程不需要等待整个数据完全写入到目标Channel就可以继续执行其他业务逻辑。

  • AIO  异步阻塞模型

      AIO需要操作系统的支持,在linux内核2.6版本中加入了对真正异步IO的支持,java从jdk1.7开始支持AIO核心类有AsynchronousSocketChannel 、AsynchronousServerSocketChannel、AsynchronousChannelGroupAsynchronousChannelGroup是异步Channel的分组管理器,它可以实现资源共享。创建AsynchronousChannelGroup时,需要传入一个ExecutorService,也就是绑定一个线程池;

该线程池负责两个任务:处理IO事件和触发CompletionHandler回调接口。

以上是关于网络编程模型(I/O模型)的主要内容,如果未能解决你的问题,请参考以下文章

网络编程之五种I/O模型

网络编程中常见的5种I/O模型

网络编程模型(I/O模型)

网络编程笔记Linux系统常见的网络编程I/O模型简述

一文读懂高性能网络编程中的I/O模型

Unix网络编程中的五种I/O模型_转