我对NIO的理解

NIO解决了两个阻塞问题:(1)IO本身的阻塞  (2)sockect.的accept阻塞;解决方案分别是新IO里面的channel/bytebuffer和selector.

问题1:

首先传统的IO是基于流的,是阻塞的,因为假设在网络应用中,如果数据没有到位(没有数据,或者不够:例如一个字节只传了第一位),而又不是流的结束(连接中断),那么这个时候read会阻塞至数据够了或者流结束或者有异常。

因此换句话说:必须读到数据,要不只能等到异常或者socket关闭返回-1,没有返回0的情况;

而新IO,可以读不到数据,可以返回0,只有等异常或者socke关系返回-1。因此不用阻塞线程。

换句话说:在socket不关闭情况下,传统IO必须读到数据,否则阻塞,而新IO可以不读到数据返回0从而不阻塞。

那么假设我们用装饰类bufferinputstream之类,是否解决了这个问题呢?其实并没有,因为理由有2个:

(1)装饰肯定以原来的inputstream为基础,既然基础的是阻塞的,那么必然也是阻塞的;

(2)例如BufferedReader.readline(),只是等于数据满足一行(遇到换行符)时,才会读出,减少不断读的代价,反而增大了要求;


从上面可以看出,传统的IO是阻塞的,那么只能借助于NIO来解决这个问题:

NIO用通道(这样仅仅是数据而已了)取代了流(字节流或者字符流),最大的特性是无阻塞的,即通道里面有多少数据就读写多少,立即返回,而不是阻塞。

(1)即使数据没有全部到位,也可以读写。

 

问题2:

select()是阻塞的,监听信道注册的感兴趣IO集发生事情(通道有读的数据,特别注意监听写的时候,是随时可以写的,取决于自己);

channel可以注册多个感兴趣IO ,对应不同的KEY, 

当执行SELECT后,在执行selectkeys()就会把发生的IO事情选取出来做掉,记住做完之后要REMOVE,否则下次发生新事件,是在老的事情基础上增加的


因为从这个角度看,

NIO核心是SELECT,屏蔽了一个线程一个连接的缺点:假设都是长连接且用户过大,导致线程过多;

同时READ/WRITE是无阻塞的,配合SELECT就解决了死等现象;


遗留一个问题:假设NIO选择READ后,我读是否直接用等于0标记读数据结束了??

 


不知道自己理解的对不对?

你可能感兴趣的:(socket,IO,网络应用)