NIO与netty原理

计算机组成原理

在这里插入图片描述

App是无法直接操作驱动等内核程序的,需要调用内核程序时,必须向内核进行系统调用。

系统调用与函数调用不是同一个东西。

由于保护模式的存在,我们的程序是无法直接函数调用内核程序,而是通过系统调用。

系统调用,本质就是通过中断执行。

程序中断的过程:

  1. 程序中,仿佛函数调用似的调用内核程序,(本质上会产生中断)

  2. 系统调用产生中断,中断将内核程序的中断向量(0~255)存入CPU的寄存器

  3. CPU同时会开启一个守护线程,守护我们的程序,以将中断的结果返回

  4. CPU根据中断向量,在中断向量表找到对应内核程序的启动地址,调用此内核程序

  5. 根据守护线程,将结果放回给我们的程序。

在整个过程中,我们如同函数调用般的使用了内核程序,而实际上发生了以上这么多东西。

影响CPU吞吐量:

  1. 线程过多,浪费在切换线程上
  2. 中断过多,同样浪费在上下文切换上

服务器的阻塞

来看最原始的ServerSocker(BIO)

在这里插入图片描述

阻塞有两个

  1. server.accpet(),等待客户端连入。
  2. reader.readline() 等待客户端输入。需要多线程执行客户端请求的服务,因为IO会阻塞,不多线程会影响下一个连入的客户端。

几个比较有用的linux命令

strace -ff -o out /usr/jdk1.8/bin/java TestSocket 
#ff 代表for fork ,监控当前所有线程的所有系统调用
#-o out 将系统调用记录写成日志文件
#/bin/java 为jvm
#TestSocket 为我们编译好的.class 记得先用javac编译

在这里插入图片描述

可以看到,Java本身就是多线程的,在jdk1.4中,启动一个Java程序自带8个线程(守护线程,监控线程等等)。

socket系统调用成功后,会返回一个数字,这个数字叫做file descriptor。这个数字就是表示代表这个socket。其他生成作用的系统调用同样会产生file descriptor

bind等系统调用,会直接使用file descriptor

  • bind ():将某个socket和端口绑定
  • listen() :开启某个端口的监听
  • accept() :等待端口的下一个client连接(会阻塞),并为新来的clinet分配file descriptor
  • recv() : 等待IO输入
netstat -natp

在这里插入图片描述

nc localhost 8090
#nc会帮我们建立一个TCP连接 8090是clinet使用的端口

BIO

在这里插入图片描述

无论是BIO,NIO,AIO,每当服务器启动时,必然会系统调用这三个内核程序

socket => file descriptor
bind(file descriptor,port)
listen(file descriptor)

BIO,每当有一个client连接,就要新建一个轻量级线程,来处理此客户端I/O(因为IO阻塞,假如不多线程,直接在主线程执行,只要有一个塞住,那无法调用accept,后面的全部塞住。)。

无论是BIO,NIO,AIO,一旦accept了client,就会为这个client分配一条TCP连接,TCP连接可以是新建的,也可以是连接池(TCP长连接)中得到的。

缺点:

  • 线程过多,线程内存浪费
  • 切换线程、CPU调度消耗
  • 根源在于:Blocking IO -> 受制于内核 accept,recv
  • 假如不多线程,直接阻塞,可能会把TCP连接池占光。

NIO

在这里插入图片描述

socketChannel.configureBlocking(false
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值