现在的位置: 首页 > 综合 > 正文

基于消息实现系统间的通信(BIO,NIO,AIO)学习。

2018年01月23日 ⁄ 综合 ⁄ 共 2516字 ⁄ 字号 评论关闭

基于消息的方式实现系统间的通信

当系统之间要通信时,就向外发送消息,消息可以是字节流,字节数组,甚至是java对象,其他系统接受消息后,则进行相应的业务处理。

消息方式的系统间通信,通常基于网络协议来实现,常用的实现系统间的通信协议有:TCP/IP 和UDP/IP。

TCP/IP是一种可靠的网络数据传输协议。TCP/IP要求通信双方首先建立连接(通过三次握手协议),之后再进行数据的传输。TCP/IP保证数据传输的可靠性,包括数据的可到达,数据到达的顺序等,如何保证呢?涉及到TCP报文格式,滑动窗口方式的传输,超时重传,选择确认等计算机网络知识。

UDP/IP是一种不保证数据一点到达的网络数据传输协议。UDP/IP并不直接给通信的双方建立连接,而是发送到网络上进行传递。由于UDP不建立连接,并且不能保证数据传输的可靠,性能表现相当较好,但可能出现数据丢失以及数据乱序的现象。

TCP/IP可以用于完成系统间数据的传输,但是,要完成系统间的通信,还需要对数据进行处理。比如读取和写入数据,按照POSIX标准,分为同步IO和异步IO,其中同步IO中最常用的是BIO(Blocking IO)和NIO(Non-Blocking IO),参考博客(http://19880512.blog.51cto.com/936364/381722http://blog.csdn.net/historyasamirror/article/details/4270633

http://blog.csdn.net/historyasamirror/article/details/5778378)。

BIO同步阻塞IO

从程序上来说,就是当发起IO的读/写的操作时,均为阻塞方式,只有当读到了流或将流写入操作系统后,才会释放资源。

在这个模型中,用户级别的应用程序执行一个系统调用,这会导致应用程序阻塞。这意味着应用程序会一直阻塞,直到系统调用完成为止(数据传输完成或发 生错误)。调用应用程序处于一种不再消费 CPU 而只是简单等待响应的状态。

以read位例,应用程序(application)为了执行这个read操作,会调用相应的一个system call,将系统控制权交给kernel,然后就进行等待(这其实就是被阻塞了)。kernel开始执行这个system call,执行完毕后会向应用程序返回响应,应用程序得到响应后,就不再阻塞,并进行后面的工作。

如上图,“在调用 read 系统调用时,应用程序会阻塞并对内核进行上下文切换。然后会触发读操作,当响应返回时(从我们正在从中读取的设备中返回),数据就被移动到用户空间的缓冲区中。然后应用程序就会解除阻塞(read 调用返回)。”

同步非阻塞IO (NIO)

NIO是基于事件驱动思想的,实现上通常采用Reactor(http://en.wikipedia.org/wiki/Reactor_pattern)模式,从程序角度而言,当发起IO的读或写操作时,是非阻塞的;当socket有流可读或可写入socket时,操作系统会相应的通知引用程序进行处理,应用再将流读取到缓冲区或写入操作系统。对于网络IO而言,主要有连接建立、流读取及流写入三种事件、linux2.6以后的版本使用epoll(http://lse.sourceforge.net/epoll/index.html)方式实现NIO。

select/epoll的好处就在于单个process就可以同时处理多个网络连接的IO。它的基本原理就是select/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。它的流程如图:

当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
这个图和blocking IO的图其实并没有太大的不同,事实上,还更差一些。因为这里需要使用两个system call (select 和 recvfrom),而blocking IO只调用了一个system call (recvfrom)。但是,用select的优势在于它可以同时处理多个connection。(多说一句。所以,如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。)
在IOmultiplexing Model中,实际中,对于每一个socket,一般都设置成为non-blocking,但是,如上图所示,整个用户的process其实是一直被block的。只不过process是被select这个函数block,而不是被socket IO给block。

AIO,异步IO方式

AIO为异步IO方式,同样基于事件驱动思想,实现上通常采用Proactor模式(http://en.wikipedia.org/wiki/Proactor_pattern

从程序的角度而言,与NIO不同,当进行读写操作时,只须直接调用API的read或write方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。较之NIO而言,AIO一方面简化了程序出的编写,流的读取和写入都由操作系统来代替完成;另一方面省去了NIO中程序要遍历事件通知队列(selector)的代价。Windows基于IOCP(http://en.wikipedia.org/wiki/Input/output_completion_port)实现了AIO,Linux目前只有基于epoll实现的AIO。

抱歉!评论已关闭.