深入理解NIO的原理

2020-06-08  本文已影响0人  南园故剑00

网络IO模型优化

最开始的阻塞式IO,它在每一个连接创建时,都需要一个用户线程来处理,并且在IO操作没有就绪或者结束时,线程被挂起,进入阻塞等待状态,阻塞式IO就成为导致性能瓶颈的根本原因。


阻塞式发生在那些环节呢?

  1. 首先,应用程序通过系统调用socket创建一个套接字,他是分配给应用程序的一个文件描述符
  2. 其次,应用程序会通过系统调用bind,绑定地址和端口号,给套接字命名一个名称
  3. 然后,系统会调用listen创建一个队列用于存放客户端进来的请求
  4. 最后,应用服务会通过系统嗲用accept来监听客户端的连接请求

当有一个客户端连接到服务端之后,服务端就会调用fork创建一个子进程,通过系统调用read监听客户端发来的消息,再通过write向客户端返回信息。

1. 阻塞式IO

在整个socket通信工作流程中,socket的默认状态是阻塞的。也就是说,当发出一个不能立即完成的套接字调用时,其进程将被阻塞,被系统挂起,进入睡眠状态,一直等待响应的操作响应。

connect阻塞:

当客户端发起TCP请求,通过系统调用connect函数,TCP连接的建立需要完成三次握手过程,客户端需要等待服务端发送过来的ACK以及SYN信号,同样服务端也需要阻塞等待客户端连接的ACK信号,这就意味着会阻塞等待,直到确认连接。


accept阻塞:

一个阻塞的socket通信的服务端接收外来连接,会调用accept函数,如果没有新的连接到达,调用进程将被挂起,进入阻塞状态。


read、write阻塞

当一个socket连接创建成功之后,服务端用fork函数创建一个子进程,调用read函数等待客户端的数据写入,如果没有数据写入,调用子进程将被挂起,进入阻塞状态。


2. 非阻塞式IO

3. IO复用

select()函数

epoll()函数

4. 信号驱动式IO

信号驱动式IO类似于观察者模式,内核就是一个观察者,信号回调则是通知。用户进程发起一个IO请求操作,会通过系统调用sigaction函数,给对应的套接字注册一个信号回调,
此时不阻塞用户进程,进程会继续工作。当内核数据就绪时,内核就为该进程生成一个SIGIO信号,通过信号回调通知进行相关IO操作。


5. 异步IO

在 NIO 服务端通信编程中,首先会创建一个 Channel,用于监听客户端连接;接着,创建多路复用器 Selector,并将 Channel 注册到 Selector,程序会通过 Selector 来轮询注册在其上的 Channel,当发现一个或多个 Channel 处于就绪状态时,返回就绪的监听事件,最后程序匹配到监听事件,进行相关的 I/O 操作。


上一篇 下一篇

猜你喜欢

热点阅读