Java NIO 笔记

0. 存在多种通道,key.channel()返回的是该事件的宿主,如果key是OP_ACCEPT事件,则返回的会是ServerSocketChannel.

1. SelectionKey.cancel  : cancel()方法是永久的注销SelectionKey.OPxxxx,并将其放入selector的canceled set中。在下一次调用select()方法的时候,这些键会从该选择器的所有键集中移除,它关联的信道也不在监听了(除非它又重新注册)。

2.NIO HTTP Server Example :

import java.io.*;

import java.nio.*;

import java.nio.channels.*;

import java.util.Iterator;

import java.net.*;



public class NonblockingSingleFileHTTPServer {



  private ByteBuffer contentBuffer;

  private int port = 80;



  public NonblockingSingleFileHTTPServer(

   ByteBuffer data, String encoding, String MIMEType, int port) 

   throws UnsupportedEncodingException {

    

    this.port = port;

    String header = "HTTP/1.0 200 OK\r\n"

     + "Server: OneFile 2.0\r\n"

     + "Content-length: " + data.limit( ) + "\r\n"

     + "Content-type: " + MIMEType + "\r\n\r\n";

    byte[] headerData = header.getBytes("ASCII");



    ByteBuffer buffer = ByteBuffer.allocate(

     data.limit( ) + headerData.length);

    buffer.put(headerData);

    buffer.put(data);

    buffer.flip( );

    this.contentBuffer = buffer;

    

  }

  

  public void run( ) throws IOException {

  

    ServerSocketChannel serverChannel = ServerSocketChannel.open( );

    ServerSocket  serverSocket = serverChannel.socket( );

    Selector selector = Selector.open( );

    InetSocketAddress localPort = new InetSocketAddress(port);

    serverSocket.bind(localPort);

    serverChannel.configureBlocking(false);
    
    //服务端通道只注册accept事件
    serverChannel.register(selector, SelectionKey.OP_ACCEPT);



    while (true) {

    

      selector.select( );
      
      Iterator keys = selector.selectedKeys( ).iterator( );

      while (keys.hasNext( )) {

        SelectionKey key = (SelectionKey) keys.next( );
        //一定要删除已处理过的事件,否则下一次select仍然会提交给你
        keys.remove( );

        try {

          if (key.isAcceptable( )) {

            ServerSocketChannel server = (ServerSocketChannel) key.channel( );

            SocketChannel channel = server.accept( );

            channel.configureBlocking(false);
            //给客户端通道注册可读事件
            SelectionKey newKey = channel.register(selector, 

                                                   SelectionKey.OP_READ);

          }

          else if (key.isWritable( )) {
        	
        	
        	
            SocketChannel channel = (SocketChannel) key.channel( );

            ByteBuffer buffer = (ByteBuffer) key.attachment( );
            synchronized (buffer) {
				
			
            
           
            if (buffer.hasRemaining( )) {
            
            	//可写则写
               channel.write(buffer);   

            }

            else {  // we're done
            	//写完关闭客户端连接
                channel.close( );   
            	
            }
            }

          }

          else if (key.isReadable( )) {

            // Don't bother trying to parse the HTTP header.

            // Just read something.

            SocketChannel channel = (SocketChannel) key.channel( );

            ByteBuffer buffer = ByteBuffer.allocate(4096); 

            channel.read(buffer);
            //buffer.flip();
            //System.out.println(new String(buffer.array()));

            // switch channel to write-only mode
            
            
            //更改为只注册可写事件

            key.interestOps(SelectionKey.OP_WRITE);

            key.attach(contentBuffer.duplicate( ));

          }

        }

        catch (IOException ex) {
        	ex.printStackTrace();
        	
          //取消key所对应的事件
          key.cancel( );

          try {
        	  
            key.channel( ).close( );

          }

          catch (IOException cex) {
        	  cex.printStackTrace();
        	  
          }

        }

      }

    }

  }

  

  public static void main(String[] args) {


	args = new String[]{"I:\\说明_Readme.html","801","gb2312"};
    if (args.length == 0) {

      System.out.println(

        "Usage: java NonblockingSingleFileHTTPServer file port encoding"); 

      return;

    }

      

    try {

      String contentType = "text/plain";

      if (args[0].endsWith(".html") || args[0].endsWith(".htm")) {

        contentType = "text/html";

      }

      

      FileInputStream fin = new FileInputStream(args[0]);

      FileChannel in = fin.getChannel( );

      ByteBuffer input = in.map(FileChannel.MapMode.READ_ONLY, 0, in.size( ));

        

      // set the port to listen on

      int port;

      try {

        port = Integer.parseInt(args[1]);

        if (port < 1 || port > 65535) port = 80;

      }  

      catch (Exception ex) {

        port = 80;

      }  

      

      String encoding = "ASCII";

      if (args.length > 2) encoding = args[2]; 

       

      NonblockingSingleFileHTTPServer server

       = new NonblockingSingleFileHTTPServer(

         input, encoding, contentType, port);

      server.run( );         



    }

    catch (Exception ex) {

      ex.printStackTrace( );

      System.err.println(ex);

    }

  

  }



}
原文地址:https://www.cnblogs.com/yangyh/p/2165946.html