星球狂想战队|深度解读Netty:NIO那些不为人知的秘密

作者丨一枝花算不算浪漫
来源:
前言这段时间一直在学习Netty相关知识 , 因为涉及知识点比较多 , 也走了不少弯路 。 目前网上关于Netty学习资料琳琅满目 , 不知如何下手 , 其实大家都是一样的 , 学习方法和技巧都是总结出来的 , 我们在没有找到很好的方法之前不如按部就班先从基础开始 , 一般从总分总的渐进方式 , 既观森林 , 又见草木 。
Netty是一款提供异步的、事件驱动的网络应用程序框架和工具 , 是基于NIO客户端、服务器端的编程框架 。 所以这里我们先以NIO和依赖相关的基础铺垫来进行剖析讲解 , 从而作为Netty学习之旅的一个开端 。
一、网络编程基础回顾1.Socket
Socket本身有“插座”的意思 , 不是Java中特有的概念 , 而是一个语言无关的标准 , 任何可以实现网络编程的编程语言都有Socket 。 在Linux环境下 , 用于表示进程间网络通信的特殊文件类型 , 其本质为内核借助缓冲区形成的伪文件 。 既然是文件 , 那么理所当然的 , 我们可以使用文件描述符引用套接字 。
与管道类似的 , Linux系统将其封装成文件的目的是为了统一接口 , 使得读写套接字和读写文件的操作一致 。 区别是管道主要应用于本地进程间通信 , 而套接字多应用于网络进程间数据的传递 。
可以这么理解:Socket就是网络上的两个应用程序通过一个双向通信连接实现数据交换的编程接口API 。
Socket通信的基本流程具体步骤如下所示:
(1)服务端通过Listen开启监听 , 等待客户端接入 。
(2)客户端的套接字通过Connect连接服务器端的套接字 , 服务端通过Accept接收客户端连接 。 在connect-accept过程中 , 操作系统将会进行三次握手 。
(3)客户端和服务端通过write和read发送和接收数据 , 操作系统将会完成TCP数据的确认、重发等步骤 。
(4)通过close关闭连接 , 操作系统会进行四次挥手 。
针对Java编程语言 , java.net包是网络编程的基础类库 。 其中ServerSocket和Socket是网络编程的基础类型 。
SeverSocket是服务端应用类型 。 Socket是建立连接的类型 。 当连接建立成功后 , 服务器和客户端都会有一个Socket对象示例 , 可以通过这个Socket对象示例 , 完成会话的所有操作 。 对于一个完整的网络连接来说 , Socket是平等的 , 没有服务器客户端分级情况 。
2.IO模型介绍
对于一次IO操作 , 数据会先拷贝到内核空间中 , 然后再从内核空间拷贝到用户空间中 , 所以一次read操作 , 会经历两个阶段:
(1)等待数据准备
(2)数据从内核空间拷贝到用户空间
基于以上两个阶段就产生了五种不同的IO模式 。
阻塞IO:从进程发起IO操作 , 一直等待上述两个阶段完成 , 此时两阶段一起阻塞 。 非阻塞IO:进程一直询问IO准备好了没有 , 准备好了再发起读取操作 , 这时才把数据从内核空间拷贝到用户空间 。 第一阶段不阻塞但要轮询 , 第二阶段阻塞 。 多路复用IO:多个连接使用同一个select去询问IO准备好了没有 , 如果有准备好了的 , 就返回有数据准备好了 , 然后对应的连接再发起读取操作 , 把数据从内核空间拷贝到用户空间 。 两阶段分开阻塞 。 信号驱动IO:进程发起读取操作会立即返回 , 当数据准备好了会以通知的形式告诉进程 , 进程再发起读取操作 , 把数据从内核空间拷贝到用户空间 。 第一阶段不阻塞 , 第二阶段阻塞 。 异步IO:进程发起读取操作会立即返回 , 等到数据准备好且已经拷贝到用户空间了再通知进程拿数据 。 两个阶段都不阻塞 。这五种IO模式不难发现存在这两对关系:同步和异步、阻塞和非阻塞 。 那么稍微解释一下:
同步和异步
同步:同步就是发起一个调用后 , 被调用者未处理完请求之前 , 调用不返回 。 异步:异步就是发起一个调用后 , 立刻得到被调用者的回应表示已接收到请求 , 但是被调用者并没有返回结果 , 此时我们可以处理其他的请求 , 被调用者通常依靠事件 , 回调等机制来通知调用者其返回结果 。同步和异步的区别最大在于异步的话调用者不需要等待处理结果 , 被调用者会通过回调等机制来通知调用者其返回结果 。