BIO

阻塞等待连接/数据,读写都阻塞、耗带宽和资源,每个请求过来开一个线程阻塞

NIO

  • 非阻塞IO,可能等的时间太久响应延迟大会重试-多路复用,通道buffer多路复用、监听事件
  • NIO多路复用:便捷的通知机制,程序注册一组socket文件描述符给OS,表示“我要监视这些fd是否有IO事件发生,有了就告诉程序处理”

    • select:遍历判断事件是否可达然后继续
    • poll:做了优化,水平触发问题
    • epoll:有状态,会创建文件描述符指向的表,监听增删改查,无并发限制、非轮询、内存拷贝,支持水平和边缘触发

      粘包/拆包

  • 换行符

  • 消息头声明长度
  • 固定报文长度补齐空位

    AIO/NIO2(异步IO)

    序列化

    I/O模型

    前置知识

    创建进程分配空间
    低地址位:用户空间,高地址位:内核空间
    虚拟内存
    image.png
    通过MMU维护的页表转成真正内存
    Linux 4K内存页

阻塞的本质:将task_struct移出运行队列,添加到等待队列,在内核注册回调事件,并将进程状态修改,重新出发CPU调度让渡。当事件触发(数据拷贝到内核中准备好了),触发硬件中断,内核调用回调函数唤醒进程重新加入运行队列,修改状态(过程中可能包含网卡拷贝到内核,内核向用户空间堆上拷贝数据,java涉及堆和非堆更复杂)

网络分为应用层(java)->Socket层->协议层->网络层

IO底层2大步骤:

  • 数据准备阶段:用户线程等待内核将数据从网卡拷贝到内核空间
  • 数据拷贝阶段:内核将数据从内核空间拷贝到用户空间(应用进程缓冲区)

image.png
各种I/O模型核心解决问题是内存和外部IO设备的速度差异问题

I/O模型阻塞点考虑的是数据准备阶段
等着拷完就是阻塞,立即返回状态就是非阻塞

I/O模型同步异步考虑的是数据拷贝阶段
内核主动发起(拷到用户空间后通知)——异步,应用程序触发(询问)——同步

多路复用——同步

image.png

Socket不同的计算机节点之间通信的端点(Endpoint)的抽象,linux是一个文件,通信就相当于往两个文件中读写
ServerSocket->调用C创建Socket->bind端口->listen端口->循环accept()三次握手

select 轮询O(n),数组一般1024个
poll 改进不大,65535实际无上限
epoll(eventpoll(wq等待队列,rdlist双向链表存储就绪socket的epitem,rbr红黑树存储监视socket的epitem))实现多路复用IO,65535实际无上限
三大方法:epoll_create/epoll_ctl/epoll_wait(LT/ET->事件就绪队列)
ET边沿触发/LT水平触发:epoll支持ET,事件通知方式不同,LT持续通知直到处理事件完毕,ET只通知一次,不管事件是否处理完毕,ET使得就绪队列上的新的就绪事件能被快速处理,避免共享 “epoll fd” 场景下,发生类似惊群问题
网络模型 - 图4

selector 多路复用选择器 selecor.select() handler

单Reactor模型
image.png
线程池Reactor模型
image.png
多(主从)Reactor模型——Tomcat
image.png
全连接
半连接