JAVA NIO 的理解学习

java nio 基于事件机制监听 不同的channel 的动作从而做出相应的响应。响应线程无需像传统io阻塞等待响应。主要涉及到的是 Buffer,Channel 以及Selector 

其中 Buffer 是缓冲器,数据的读写都必须从channel 经过buffer 获取或者写入channel中。

Channel 基于Nio 必须是无阻塞的 每一个客户端和服务端连接都回在服务端新建一个socketChannel,并通过 channel.register(selector,eventKey) 注册到Selector.selector 可以单线程 阻塞监听是否有事件发生,如果存在 调用事件注册的 服务进行相应的处理。

核心在于Selector。

以下是写的测试类:

package com.hrd.nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.UUID;

/**
 * 服务端和客户端 分别启动一个SelectorThread 用于监听事件,这里由于本机写成一个。
 * @author hurd@omeng.cc
 * @version v0.1
 * @date 2016/8/16
 * @desc TODO
 * @see
 */
public class SelectThread extends Thread {

    private String threadName;
    private Selector selector;

    public SelectThread(String threadName, Selector selector){
        this.threadName = threadName;
        this.selector = selector;
    }

    @Override
    public void run() {

        Thread.currentThread().setName(threadName);

        try {
            while(true){
                //阻塞
                selector.select();
                //获取选择器中已经就绪的SelectionKey集合
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                //遍历
                while (iterator.hasNext()){
                    SelectionKey key = iterator.next();
                    //删除
                    iterator.remove();
                    //接受连接就绪事件
                    if(key.isAcceptable()){
                        ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
                        SocketChannel socketChannel = ssc.accept();
                        //套接字通道设置为非阻塞模式
                        socketChannel.configureBlocking(false);
                        //向socket通道 注册读就绪事件
                        socketChannel.register(selector, SelectionKey.OP_READ);
                    }else if(key.isReadable()){
                        //SocketChannel socketChannel = (SocketChannel) key.channel();
                        ByteBuffer byteBuffer = ByteBuffer.allocate(100);
                        ((SocketChannel)key.channel()).read(byteBuffer);
                        //将写模式变为读模式
                        byteBuffer.flip();
                        //读取完毕
                        if(byteBuffer.limit()>0){
                            System.out.println("线程:"+Thread.currentThread().getName()+"消息:" + new String(byteBuffer.array()).trim());
                        }
                        key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
                    }else if(key.isWritable()){
                        //暂时还没想明白这个写就绪事件干嘛用的。。。
                        System.out.println("写就绪事件触发了,线程名:"+Thread.currentThread().getName());
                        ByteBuffer byteBuffer = ByteBuffer.allocate(1000);
                        byteBuffer.put((Thread.currentThread().getName() + UUID.randomUUID().toString()).getBytes());
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        byteBuffer.flip();
                        socketChannel.write(byteBuffer);
                        key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
                    }else if(key.isConnectable()){
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        //判断连接是否完成
                        int i =0;
                        while(! socketChannel.finishConnect()){
                            if(++i>10){
                                throw  new RuntimeException("socket连接超时");
                            }
                            System.out.println("sock连接未完成,等待中....");
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        //向socket通道 注册读就绪事件
                        socketChannel.register(selector, SelectionKey.OP_READ);
                        ByteBuffer byteBuffer = ByteBuffer.allocate(100);
                        byteBuffer.put((Thread.currentThread().getName()+"客户端完成连接啦,感谢服务端哈").getBytes());
                        byteBuffer.flip();
                        socketChannel.write(byteBuffer);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
package com.hrd.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;

/**
 * @author hurd@omeng.cc
 * @version v0.1
 * @date 2016/8/16
 * @desc TODO
 * @see
 */
public class ServerSocketMain {

    public static void main(String[] args) throws IOException, InterruptedException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);

        //绑定 ip 地址
        serverSocketChannel.bind(new InetSocketAddress(8888));
        //注册感兴趣的事件 这里注册 注册accept 和读就绪事件
        Selector selector = Selector.open();
        SelectThread threadThread = new SelectThread("server side",selector);
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        //服务端阻塞监听selector 事件
        threadThread.start();
        serverSocketChannel.accept();

        System.out.println("服务端socket 启动完成....");
        // wait 主线程 后续的操作交给子线程处理
        synchronized (Thread.currentThread()){
            Thread.currentThread().wait();
        }

    }
}
package com.hrd.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

/**
 * @author hurd@omeng.cc
 * @version v0.1
 * @date 2016/8/16
 * @desc TODO
 * @see
 */
public class ClientSocketMain {

    public static void main(String[] args) throws IOException, InterruptedException {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);

        socketChannel.connect(new InetSocketAddress(8888));
        Selector selector =  Selector.open();

        SelectThread clientSelectThread = new SelectThread("client side:",selector);

        socketChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ);

        clientSelectThread.start();

        System.out.println("客户端启动完成....");
        synchronized (Thread.currentThread()){
            Thread.currentThread().wait();
        }

    }
}

 

转载于:https://my.oschina.net/ehomeud/blog/733624

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值