nio笔记

http://blog.csdn.net/z69183787/article/category/2191483此人的博客

 

 

 首先你要知道阻塞和非阻塞的概念,阻塞体现在这个线程不能干别的了,只能在这里等着。非阻塞体现在这个线程可以去干别的,不需要一直在这等着。
说NIO的非阻塞原理之前,我们需要先说一下传统的io。传统的IO是按字节传输的,即每次传输一个字节。为了提高数据传输效率,引进了带缓冲区得输入输出模式,这样每次就可以传输大量的字节数,

但是,会导致在读(写)缓冲区没有满的情况下,程序会一直等待,直到满或者关闭流才能读取(写入)。这样导致程序阻塞,降低了程序的执行效率。、

 

 

非阻塞模式  使一个线程可以同时处理多个通道, 通道accept  read  write 没有连接,读写数据不够或者没有时都直接返回,不用阻塞等待。

 

同步:线程需要的等待返回结果  

异步:如果有返回结果,线程会得到通知

 

 

阻塞:方法不会立即返回结果

非阻塞:不论是否有结果   方法都会返回一个信息

 

 

 

 

1.使用通道:  fileinputstream.getChannel()    打开的文件通道只有读权限,没有写权限,如果写,报异常,不要执行写操作。

   注意读写权限问题。

FileInputStream input = new FileInputStream (fileName);

FileChannel channel = input.getChannel( );

// This will compile but will throw an IOException

// because the underlying file is read-only

channel.write (buffer);

 

2.只有流通道: sockets  pipes可以非阻塞模式, 文件通道总是阻塞式的, 文件io最强大之处在于:异步io,一个进程可以请求多个io操作。

阻塞是I/O操作阻塞,      当前通道正在执行io操作,其他io操作则阻塞,  非阻塞则会返回null

 

 

3.文件 进程级别。

 

4.reigster 注册通道时,如果已经注册过,则更新,如果已经注册且 selectionkey已经被cancel, 则报异常。

key.cancel();
ssc.register(selector, SelectionKey.OP_ACCEPT);

抛异常

 一个通道可以被注册到多个选择器上,但对每个选择器而言只能被注册一次。

 

 

5.每次迭代的末尾调用keyIterator.remove()

例如:首次调用select()方法,如果有一个通道变成就绪状态,返回了1,若再次调用select()方法,如果另一个通道就绪了,它会再次返回1。如果对第一个就绪的channel没有做任何操作,现在就有两个就绪的通道,但在每次select()方法调用之间,只有一个通道就绪了。

 

 

6.向selector注册通道时,通道必须是非阻塞模式

configblocking(false)

 

注意点:

1.it.remove();

 

2.想关闭channel, 用key.cancel()

key.cancel()  下次select会取消这个key相关的信息, channel也会注销

 

3.多线程处理时:

key.interestOps(key.interestOps() & (~SelectionKey.OP_READ));

处理完成后

key.interestOps(key.interestOps() | SelectionKey.OP_READ);
key.selector().wakeup();

 

4.   流末尾返回-1;     while(buffer.hasremaining())写数据 

while(source.read(buffer) != -1) {
buffer.flip();
while(buffer.hasRemaining()) {
dest.write(buffer);
}
buffer.clear();
}

 

5.

 String question = new String(readBuffer.array());    array 是返回整个buffer内容

 CharBuffer charBuffer = CharsetHelper.decode(readBuffer);   返回position--limit的内容

 

6.

/*当客户端channel关闭后,会不断收到read事件,但没有消息,即read方法返回-1                

* 所以这时服务器端也需要关闭channel,避免无限无效的处理*/    

try{

  if((channel.read(buffer) )  > 0 ){

  } else {

    //关闭channel, 因为客户端已经关闭channel或者已经异常

    channel.close();

  }

}catch(Exception e){

  if(channel != null) {

    channel.close();

  }

}

 

7.

 channel.write(CharsetHelper.encode(CharBuffer.wrap(answer))); 

 

8

.channel.open   configblocking(false)   connect()  不要简写或改顺序

  1. if(selector == null)   
  2.     selector = Selector.open();   
  3. SocketChannel channel = SocketChannel.open();   
  4. channel.configureBlocking(false);   
  5. channel.connect(new InetSocketAddress("localhost", 1234));   
  6. channel.register(selector, SelectionKey.OP_CONNECT);  

 

  1. //连接事件   
  2. if(key.isConnectable()) {   
  3.     SocketChannel socketChannel = (SocketChannel) key.channel();   
  4.     if(socketChannel.isConnectionPending())   
  5.         socketChannel.finishConnect();   
  6.     socketChannel.write(ByteBuffer.wrap(serverFileName.getBytes()));//向服务器发信息,信息中即服务器上的文件名   
  7.     socketChannel.register(selector, SelectionKey.OP_READ);   
  8. }  

 

posted @ 2017-08-07 18:02  上台阶  阅读(217)  评论(0编辑  收藏  举报