初识Netty-前置知识

一、基本概念

          

1、IO的概念

  • input-读入数据:线程从某个源头读入数据放到缓冲区
  • output-输出数据:线程向某个目的地输出缓冲区内的数据

注:输入输出数据一般都需要操作系统支持,有些特殊情况不需要,如嵌入式(无操作系统)

2、 IO模型

     数据不会自主地从缓冲区进出到外部设备中,因此需要有线程等类似的驱动者去驱动数据的流动,即数据在线程驱动下,从缓冲区通过端口(如socket或其他)进出到外部设备,而IO的参照对象是缓冲区Buffer,进Buffer为读入,出Buffer为输出

  • 驱动者:驱动数据输入输出的线程或进程或控制流(cpu或类似的东西)
  • Buffer:缓冲区
  • socket:端口

       

3、IO的同步异步和阻塞非阻塞

(1)同步和异步

  标准:不同的动作是否按照固定的顺序执行,同步是按照固定顺序执行,俗称排队,异步反之

             IO概念中即是指,在IO请求返回和IO动作尝试之间是否有一个明确的顺序

  • 同步:IO请求返回的时候,IO尝试动作已经做完了,即返回的动作明确发生在IO尝试之后
  • 异步:请求返回只表明收到了请求,对实际的IO尝试不做任何保证,即在请求结果返回之前,IO动作可能其实已经做完了。如光纤传数据,有可能发送数据的指令刚做完,IO光纤就已经将数据发送完了,而cpu还正在执行return代码

       异步举例:Linux的AIO是纯异步的,其他IO基本都是同步的

       可参见:linux AIO_aio linux_西门吹大雪的博客-CSDN博客 

(2)IO阻塞和非阻塞 

     一般在同步下才有意义

  • 阻塞:彻底完成IO动作,或达到某个条件(如超时),或发生错误之后才返回请求
  • 非阻塞:尝了IO的动作后就返回请求,不保证全部IO动作都完成之后才返回

(3)组合

  • 同步+阻塞:IO动作既是按照顺序执行的又保证每个IO动作有个终结性结果才返回请求(一般)
  • 同步+非阻塞:动作按顺序执行,但不保证每个IO动作有个终结性结果才返回请求(多线程)
  • 异步+阻塞:动作不按顺序执行,但每个IO动作有个终结性结果才返回请求
  • 异步+非阻塞:动作既不按照顺序执行,也不保证每个IO动作有个终结性结果才返回请求

二、各层的IO

       

  

(一)操作系统OS中IO(POSIX接口为例)

                    

1、特点

  • 操作系统提供了封装好的IO操作接口,屏蔽了IO动作细节
  • 接口为文件形式操作接口:open、close、read、write、ioctl(一切皆文件)
  • 应用线程或进程自己去确定调用IO接口的时机(驱动方为线程或进程)
  • 提供稳定的同步(阻塞或非阻塞)IO接口(默认阻塞)和异步接口(AIO)

 2、同步阻塞IO接口

(1)特点

  • 阻塞模式下,一个线程处理一个对象
  • 响应最快,cpu资源最省

 (2)问题

     需要处理的IO对象多了,就需要很多的线程,随之而来多线程的问题:

  • 线程内存消耗(每个线程都需要对应的内存)
  •  线程调度操作变多
  • 线程/进程切换会导致Cache line,进程内存映射的TLB块表失效等问题,需要大量的cpu来处理线程切换

                             

(3)解决多线程带来的资源损耗问题--减少线程数

  • IO对象设置为同步非阻塞模式,提供专门的轮询线程去管理所有需要做IO的端口并交给对应的业务线程去做
  • 问题:IO操作是没有时表不确定的,因此大量cpu浪费在轮询上,如果设置轮询线程的sleep时间,又会增加响应时间

                                

 (4)解决轮询线程空转问题---通知机制select

  • 由于IO的状态变化是通过OS的动作来的,因此通过OS内核的支持将轮询改为通知
  • 这样的通知机制抽象为一个IO状态通知器(同步阻塞/非阻塞形式的接口)
  • 特点:

<1>通知器本身不做任何IO操作,只负责状态变更通知管理

<2>接口的形式与OS强相关

           

                               

  注:上述方法讲述的是如何用更少的线程 解决更多的IO,另一种方式是通过减少资源消耗大方面,让线程变得轻量级,从内核级别到用户级别:


用户级线程,
Windows Fiber
,协程,用户级通知库
libevent

Java 中Project Loom, go中
Goroutine
,
Erlang


内核
/

内核

软件固件化(电路的并行化特点)

(二)JAVA中IO

1、JVM层

  • JAVA基于虚拟机,屏蔽系统差异性,操作系统解决的问题在虚拟机层面上要重新解决一次(JAVA的接口形式提供)
  • 一个java的线程对应一个OS的线程
  • IO(OIO) ----线程太多开销大----轮询线程CPU浪费----提供IO通知器的新IO(NIO)

2、OIO和NIO的类

(1)OIO(包括同步阻塞BIO和同步非阻塞)

java.net.ServerSocket

java.net.Socket

java.net.DatagramSocket

(2)NIO

java.nio.Buffer

java.nio.channels.Channel

java.nio.channels.Selector

3、两个IO对比

(1)OIO

     OIO中的Socket基于OS的同步IO接口完成IO动作,提供的是流式的接口,不是基于buffer

(2)NIO


各种
Channel
基于
OS
的同步
IO
接口做
IO
动作

Java
又基于
OS
提供的通知机制,面向用户提供纯
Java
语言统一的
IO
通知接口
Selector

在不同的
OS
上依赖的接口是不一样的

           

3、详解NIO

(1)NIO的使用

SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("localhost", 80));
//默认是同步阻塞的,设置成非阻塞模式,防止selector阻塞在channel中
channel.configureBlocking(false);

Selector selector = Selector.open();
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);

while(true) {
	int readyChannels = selector.selectNow();
	if(readyChannels == 0) continue;
	Set<SelectionKey> selectedKeys = selector.selectedKeys();
	Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
	while(keyIterator.hasNext()) {
	  SelectionKey key = keyIterator.next();
	  if(key.isReadable()) {
	      // a channel is ready for reading
	      ..... //Dispatch to process reading
	  } 
	  keyIterator.remove();
    } 
  }
}

(2)流程图

                

 (3)组成

  • Buffer---最基础的实现为ByteBuffer,可以理解为扩展了功能的byte数组(byte[]),支持字节转换成其他基本类型 

                                       

        注:directBuffer较heapBuffer少一次copy,为保证数据一致性,对于堆内的数据受GC影响,因此使用堆数据之前先将堆内的数据copy到用户区,然后再进行后续操作

 

  • selector---java层面实现的IO通知器 

<1>定义了4种可以侦听和通知的事件,当通知某个Channel发生了事件时,准确的含义是“这个Channel准备好了做这个事件”:Accept, Connect, Read, Write 

<2>当Channel被注册到Selector上时,会获得一个SelectionKey,作为存根,以便后续的操作


InterestSet
,
感兴趣,也就是期望侦听的事件

ReadySet
,准备好了的事件

Selector

Channel

AttachedObject
(
即用户自定义数据
)

 <3>选择(侦听)动作(方法)


int
select()

i
nt
select(long
timeout
)

i
nt
selectNow
()

<4>唤醒等待中的Selector


有期望的事件发生

其他线程调用
wakeUp
()
或者
close()

有异常发生

(三)Nettyt中IO

   三层IO的调用关系:


版权声明:本文为qq_44641527原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>