JavaNio

NIO

成 员: 

  • 通道( Channel)     
  • 缓冲区(buffer)     缓冲区本质上是一个内存块
  • 选择器 (selector) 【多路复用】 

 

通道  ->注册(事件)  ->选择器 ;

通道(数据)   <-写入 <- 缓存区   -> 读-> 通道(数据)

选择器  ->  监听  -> 通道注册 ((数据))

 

 

读写通常步骤:

1. 将数据写入缓冲区

2. buffer.flip()

3. 读取缓冲区中的数据

4. 呼叫或buffer.clear() //重置缓冲区    buffer.compact() //重置已读数据,未读数据保留

 

文件方式NIO:

 

*通过文件获取通道,然后操作

 

RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");

    FileChannel inChannel = aFile.getChannel();

    ByteBuffer buf = ByteBuffer.allocate(48);

    int bytesRead = inChannel.read(buf);

    while (bytesRead != -1) {

      System.out.println("Read " + bytesRead);

           //缓冲区反转,将读模式变为写模式

      buf.flip();

      while(buf.hasRemaining()){

          System.out.print((char) buf.get());

      }

      //重置缓冲区,将标记位变为0;

      buf.clear();

      bytesRead = inChannel.read(buf);

    }

    aFile.close();

 

 


SocketChannel

打开套接字通道

以下是如何打开 SocketChannel

SocketChannel socketChannel = SocketChannel.open();  //打开通道

socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));//设置连接的ip  端口

 

socketChannel.configureBlocking(false);//设置非阻塞

 

关闭套接字通道

通过调用 方法关闭使用后。以下是如何完成:SocketChannelSocketChannel.close()

socketChannel.close();    

 

从套接字通道阅读

若要从 读取数据,请调用其中一种方法。下面是一个示例:SocketChannelread()

ByteBuffer buf = ByteBuffer.allocate(48);

 

int bytesRead = socketChannel.read(buf);

 

 

 

 

 

ServerSocketChannel

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

 

serverSocketChannel.socket().bind(new InetSocketAddress(9999)); //设置监听ip 端口

serverSocketChannel.configureBlocking(false);

 

while(true){

    SocketChannel socketChannel =

            serverSocketChannel.accept();

 

    if(socketChannel != null){

        //do something with socketChannel...

        }

}

 


 


ServerSocketChannel 与Selector :

 

private  ServerSocketChannel ssc;

private ServerSocket serverSocket;

private Selector selector;

 

(){

 

 //打开socket通道

ssc=ServerSocketChannel.open();

 

//获取通道关联的Socket对象

serverSocket = ssc.socket();

 

//设置非阻塞

ssc.configureBlocking(false);

 

//绑定端口

serverSocket.bind(new InetSocketAddress(NioConfig.NIO_HOST,NioConfig.NIO_PORT));//监听ip和端口

 

//设置选择器

selector=Selector.open();

// int selectkeys=(SelectionKey.OP_ACCEPT);

 

 

//获取到所有注册到选择器selector 中的 SelectionKey  然后可以获取 socketChannel

// selector.keys();

 

 

//通道绑定选择器

ssc.register(selector,SELECT_KEYS);//SELECT_KEYS =SelectionKey.OP_ACCEPT; //首先要监听连接事件才能监听其他事件

// ssc.register(selector,SelectionKey.OP_READ);

 

//获取选择器就绪的事件

while (true){

 

    //if(selector.select() > -1)

        if(selector.select(2000)  == 0){

            //监听2s 无监听事件发生

            continue;

        }

 

    //选择器事件处理

    selectHandle();

}

}

/**

* 选择器事件处理

* @throws IOException

*/

private void selectHandle() throws IOException {

 

 

    //获取所有就绪的事件的迭代器

    Iterator<SelectionKey> selectionKeys = selector.selectedKeys().iterator();

 

    //循环还有没有下一个就绪的事件

    while (selectionKeys.hasNext()){

 

        //获取下一个事件1    ---selectionKey可以获取到SocketChannel

        SelectionKey selectionKey=selectionKeys.next();

 

        //判断该事件的类型-

        if (selectionKey.isAcceptable()){

            //可连接事件处理

            acceptableHandle(selectionKey);

 

 

        }else if (selectionKey.isReadable()){

            //可读事件处理

            readableHandle(selectionKey);

 

 

        }else if (selectionKey.isConnectable()){

 

 

        }else if (selectionKey.isWritable()){

        }

 

 

        //删除调用 next方法  返回的元素;  防止重复执行相同事件

                //建议加上,否则有可能事件处理事件

        selectionKeys.remove();

    }

}

 

/**

* 可连接事件处理

* @param selectionKey

* @return

* @throws IOException

*/

private boolean acceptableHandle(SelectionKey selectionKey) throws IOException {

    SocketChannel sc=ssc.accept();

    if (sc == null){

        return false;

    }

 

    sc.configureBlocking(false); //一定要设置非阻塞,不然可能报错

 

     // int op =SelectionKey.OP_READ | SelectionKey.OP_WRITE;  //可以同时设置监听多个事件

    sc.register(selector,SelectionKey.OP_READ); //监听读 事件    

    return  true;

}

 

/**

     * 可读事件处理

     * @param selectionKey

     * @throws IOException

     */

    private  void readableHandle(SelectionKey selectionKey) throws IOException {

        SocketChannel sc=(SocketChannel)  selectionKey.channel();

        if (sc == null){

            selectionKey.cancel(); //取消Selector 注册

 

 

        }

 

        //定义1024缓冲区

        ByteBuffer bbut=ByteBuffer.allocate(1024);

        // sc1=sc;

        int len=0;

 

 

        List<byte[]> listbs=new ArrayList<>();

 

 

           try{

               while ((len=sc.read(bbut))>0){

 

                   //切换模式

                   // bbut.flip();

                   //附带标识,根据标识取数据

 

                    //ByteBuffer字节数据 转成 byte数组存入 list

                   listbs.add(ConvertUtils.bytebufferByteArray(bbut));

 

                   bbut.clear();//重置byteBuffer

               }

 

           }catch (IOException e){

               selectionKey.cancel();//取消注册

               sc.close(); //断开连接

              

               return;

           }

    }

 


SokcetChannel与 Selector:

 

**

* 步骤

* 打开SocketChannel通道

* 设置通道为非阻塞

* -获取缓冲区ByteBuffer

* -为缓冲区添加内容

* -更换缓冲区状态

* -将缓冲区推入SocketChannel通道

* -清空缓冲器

* 设置选择器

* 通道绑定选择器和监听事件类型

* 获取所有就绪事件

* 处理所有就绪事件

*/

 

public   static SocketChannel ssc;

 

(){

 

//打开socket通道

         ssc=SocketChannel.open();

         ssc.configureBlocking(false);

 

 

         // 非阻塞连接,如果立即连接成功返回true

         if (!ssc.connect(new InetSocketAddress(NioConfig.NIO_HOST,NioConfig.NIO_PORT))){

 

 

             while (!ssc.finishConnect()){ //如果 已连接

                 //暂未连接,非阻塞,循环

             }

         }

         //连接成功之后

         ReturnDate returnDate=new ReturnDate();

         returnDate.setId(-1000);

         byte[] bytes =  iSerializedObject.toByteArray(returnDate);

        ByteBuffer bb=ByteBuffer.allocate(bytes.length);

        bb.put(bytes);

        bb.flip();//byteBuffer 读写反转 变为写

        ssc.write(bb);

        bb.clear(); //重置

        bb=null;

        bytes=null;

        returnDate=null;

 

        //设置选择器

        Selector selector=Selector.open();

 

        int selectkeys=(SelectionKey.OP_READ);//设置监听事件

        //通道绑定选择器

        ssc.register(selector,selectkeys);

        //是否有就绪的事件

        while (true) {

            if(selector.select(2000) == 0){//监听2s 没有事件

               //可执行其他操作

                               continue;

             }

             //监听到事件

            //获取所有就绪的事件的迭代器

            Iterator<SelectionKey> selectionKeys = selector.selectedKeys().iterator();

            //循环还有没有下一个就绪的事件

            while (selectionKeys.hasNext()) {

                //获取下一个事件1

                SelectionKey selectionKey = selectionKeys.next();

                //读事件

                if (selectionKey.isReadable()) {

                    SocketChannel sc = (SocketChannel) selectionKey.channel();

                    ByteBuffer bbut = ByteBuffer.allocate(1024);

                    //   ByteBuffer bbut1 = ByteBuffer.allocate(1024);

                    int len = 0;

                    List<byte[]> listbs=new ArrayList<>(8);

                    while ((len = sc.read(bbut)) > 0) {

                        // 切换模式

                        // bbut.flip();

                        // bbut1.flip();

                        listbs.add(ConvertUtils.bytebufferByteArray(bbut));

                      //  System.out.println("---");

                        bbut.clear();

                      //  selector.close();

 

                    }

 

                    byte[] bs=ConvertUtils.mergeByte(listbs);

                    if (bs == null){

                        continue;

                    }

 

 

                    //接收外网消息

                    ReturnDate returnDate1= (ReturnDate) iSerializedObject.ByteArrayFrom(bs, ReturnDate.class);

 

 

 

 

                    //交给其他线程处理

                    TheadPoolFactory.t.execute(new DisposeTask(returnDate1));

                    //System.out.println("收到外网消息:"+returnDate1.getId()+";"+returnDate1.getMessage());

                }

                //

            }

        }

}

 

 

 


 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值