边缘计算基本形态
|
1、客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。 2、服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。 3、客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
4、服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。 3.1 阻塞I/O 与 非阻塞I/O 阻塞与非阻塞的区别比较明显,也很好理解。 结合I/O模型来说,阻塞I/O会一直block对应的进程直到操作完成,而非阻塞 IO在kernel 在"等待数据准备"阶段会立刻返回。 所以我们一般认为,阻塞I/O只有BIO,另外四个模型都是属于非阻塞I/O。 3.2 同步I/O 与 异步I/O 先来看看 同步I/O 和 异步I/O 的定义是什么,根据POSIX的定义:
两者的区别就在于同步I/O做 "IO operation”的时候会将process阻塞。 那么按照这个定义,我们看看前面每个模型的“关键钥匙”分析部分,可以明显看到,BIO,NIO,IO多路复用、信号驱动IO 四种模型都属于 同步IO。 因为它们在IO的第二阶段,真正执行“数据拷贝”的阶段,都是“阻塞”的。以NIO为例,在执行recvfrom这个系统调用的时候,如果kernel的数据没有准备好,这时候不会block进程。但是当kernel中数据准备好的时候,recvfrom会将数据从kernel拷贝到用户内存中,这个时候进程是被block了。 同理,信号驱动IO,当内核中IO数据就绪时以SIGIO信号通知请求进程,请求进程再把数据从内核读入到用户空间,这一步也是阻塞的。 所以,真正的异步I/O只有一个,就是AIO。当进程发起IO操作之后,就直接返回再也不管了,直到kernel发送一个信号,告诉进程说IO完成。在这整个过程中,进程完全没有被阻塞。如定义所说,不会因为IO操作阻塞。 4. Netty采用了哪种I/O模型呢? Netty 的 I/O 模型是基于非阻塞 I/O 实现的,底层依赖的是 JDK NIO 框架的多路复用器 Selector。 一个多路复用器 Selector 可以同时轮询多个 Channel,采用 epoll 模式后,只需要一个线程负责 Selector 的轮询,就可以接入成千上万的客户端。 更具体的实现方式和模型,我们下一期再展开说明。 对了,一定有同学想问,Netty为什么不采用AIO呢? 因为 AIO 的目的是希望 I/O 线程不阻塞主线程,属于异步 I/O,由内核通知 I/O 操作何时完成。AIO 适用于连接数多的且需要长时间连接的场景。 对于AIO来说,目前操作系统支持程度有限且实现起来复杂。
Netty也尝试过AIO,但是效果不是很理想,最终废弃了。 (编辑:怀化站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

