java NIO selector实例

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wzl1369248650/article/details/82287925
  1. 基础父类

需要进行selector nio编程的朋友,可以直接继承AbstractSelectorChannel 使用。
ByteBufferUtil在另一篇博客中有源码

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * Created by Thinkpad on 2018/8/28.
 */
public abstract class AbstractSelectorChannel {

    private String adress;

    private int port;

    private boolean block;

    private SelectableChannel selectableChannel;

    private Selector selector;
    //停止状态
    private boolean stop;
    //暂停状态
    private boolean pause;
    //暂停时间,单位毫秒
    private long pauseTime;
    //读取字符区
    private ByteBuffer readBuff;

    public AbstractSelectorChannel(String adress ,int port,boolean block){
        this.adress = adress;
        this.port = port;
        this.block = block;
        selectableChannel = initSelectableChannel();
    }

    public AbstractSelectorChannel(SelectableChannel selectableChannel){
        this.selectableChannel = selectableChannel;
    }

    /**
     * 初始化SelectableChannel
     */
    public abstract SelectableChannel initSelectableChannel();

    /**
     * 初始化
     */
    public void init(){
        if(readBuff == null){
            readBuff = ByteBuffer.allocate(1024);
        }
        if(selector == null){
            selector = open(0);
        }
        if(selectableChannel == null){
            selectableChannel = initSelectableChannel();
        }
    }


    /**
     * 打开选择通道
     * ServerSocketChannel只能注册OP_ACCEPT
     * DatagramChannel可以注册OP_READ| OP_WRITE
     * SocketChannel可以注册OP_CONNECT|OP_READ| OP_WRITE
     * @param ops
     */
    public Selector open(int ops){
        try {
            Selector selector = Selector.open();
            //如果为0默认取OP_ACCEPT
            ops = ops == 0 ? SelectionKey.OP_ACCEPT : ops;
            selectableChannel.register(selector,ops);
            this.selector = selector;
            return selector;
        } catch (IOException e) {
            e.printStackTrace();
            try {
                selector.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
        return null;
    }

    public void select(int pos){
        selector = open(pos);
        select();
    }


    /**
     * 开始选择通道
     */
    public void select(){
        init();
        try {
            //Channel必须是非阻塞的。所以FileChannel不适用Selector
            selectableChannel.configureBlocking(false);
            while (!isStop()) {
                isPause();
                System.out.println("开始通道选择");
                selector.select();
                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> it = keys.iterator();
                while (it.hasNext()) {
                    SelectionKey key = it.next();
                    it.remove();
                    if(key.isConnectable()){
                        System.out.println("开始连接");
                        SelectableChannel selectableChannel = connectHandle(key);
                        if(selectableChannel.isOpen()){
                            selectableChannel.register(selector, SelectionKey.OP_ACCEPT);
                        }
                    }else if (key.isAcceptable()) {
                        System.out.println("开始接收");
                        SelectableChannel selectableChannel = acceptHandle(key);
                        if(selectableChannel.isOpen()){
                            selectableChannel.configureBlocking(false);
                            selectableChannel.register(selector, SelectionKey.OP_READ);
                        }
                    }else if (key.isReadable()) {
                        System.out.println("开始读取");
                         SelectableChannel selectableChannel = readHandle(key);
                         if(selectableChannel.isOpen()){
                             key.interestOps(SelectionKey.OP_WRITE);
                         }
                    }else if (key.isWritable()) {
                        System.out.println("开始写入");
                         SelectableChannel selectableChannel = writeHandle(key);
                        if(selectableChannel.isOpen()){
                            key.interestOps(SelectionKey.OP_READ);
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                selector.close();
                selectableChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void setStop(boolean flag){
        this.stop = flag;
    }

    private boolean isStop(){
        return stop;
    }

    private void isPause(){
        if(pause){
            try {
                Thread.sleep(pauseTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                pause = false;
                pauseTime = 0;
            }
        }
    }

    public void pause(long time){
        if(time == 0){
            return;
        }
        pauseTime = time;
        pause = true;
    }

    /**
     * 链接处理
     * @param selectionKey
     * @return
     */
    public SelectableChannel connectHandle(SelectionKey selectionKey) {
        return  selectionKey.channel();
    }

    /**
     * 接收处理
     * @param selectionKey
     * @return
     */
    public SelectableChannel acceptHandle(SelectionKey selectionKey) {
        return selectionKey.channel();
    }

    /**
     * 写入数据
     * @return
     */
    public abstract String writeData();

    /**
     * 写入处理
     * @param selectionKey
     * @return
     */
    public SelectableChannel writeHandle(SelectionKey selectionKey) {
        WritableByteChannel socketChannel = (WritableByteChannel) selectionKey.channel();
        try {
            ByteBuffer byteBuffer = ByteBufferUtil.write(writeData());
            //读取前指针切换
            byteBuffer.flip();
            socketChannel.write(byteBuffer);
            System.out.println("写入:"+writeData());
        } catch (IOException e) {
            e.printStackTrace();
            try {
                socketChannel.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
        return selectionKey.channel();
    }

    /**
     * 读取数据
     * @param data
     */
    public abstract void readData(String data);

    /**
     * 读取处理
     * @param selectionKey
     * @return
     */
    public SelectableChannel readHandle(SelectionKey selectionKey) {
        ReadableByteChannel socketChannel = (ReadableByteChannel) selectionKey.channel();
        try {
            socketChannel.read(readBuff);
            String data = ByteBufferUtil.readString(readBuff);
            readData(data);
            System.out.println("received : " + data);
        } catch (IOException e) {
            e.printStackTrace();
            try {
                socketChannel.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
        return selectionKey.channel();
    }

    public String getAdress() {
        return adress;
    }

    public int getPort() {
        return port;
    }

    public boolean isBlock() {
        return block;
    }

    public SelectableChannel getSelectableChannel() {
        return selectableChannel;
    }

    public Selector getSelector() {
        return selector;
    }
}
  1. 服务端
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * Created by Thinkpad on 2018/8/27.
 */
public class SelectorService extends AbstractSelectorChannel{

    public SelectorService(String adress ,int port,boolean block){
        super(adress,port,block);
    }

    @Override
    public SelectableChannel initSelectableChannel() {
        ServerSocketChannel ssc = null;
        try {
            ssc = ServerSocketChannel.open();
            ssc.socket().bind(new InetSocketAddress(getAdress(),getPort()));
            ssc.configureBlocking(isBlock());
            return ssc;
        } catch (IOException e) {
            e.printStackTrace();
            if(ssc != null){
                try {
                    ssc.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
        return null;
    }

    @Override
    public SelectableChannel acceptHandle(SelectionKey selectionKey) {
        // 创建新的连接,并且把连接注册到selector上,而且,
        // 声明这个channel只对读操作感兴趣。
        ServerSocketChannel ssc = (ServerSocketChannel)selectionKey.channel();
        SocketChannel socketChannel = null;
        try {
            socketChannel = ssc.accept();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return socketChannel;
    }

    @Override
    public String writeData() {
        return "你好1";
    }


    @Override
    public void readData(String data) {
        //读取数据后操作
    }

    public static void main(String[] args) {
        SelectorService selectorService = new SelectorService("127.0.0.1",8000,false);
        selectorService.select();
    }
}
  1. 客服端
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;

/**
 * Created by Thinkpad on 2018/8/27.
 */
public class SelectorClient extends AbstractSelectorChannel{

    public SelectorClient(String adress ,int port,boolean block){
        super(adress,port,block);
    }

    public static void main(String[] args) throws IOException {
        SelectorClient selectorClient = new SelectorClient("127.0.0.1",8000,false);
        selectorClient.select(SelectionKey.OP_WRITE);
    }

    @Override
    public SelectableChannel initSelectableChannel() {
        SocketChannel socketChannel = null;
        try {
            socketChannel = SocketChannel.open();
            socketChannel.connect(new InetSocketAddress("127.0.0.1", 8000));
            socketChannel.configureBlocking(isBlock());
            return socketChannel;
        } catch (IOException e) {
            e.printStackTrace();
            if(socketChannel != null){
                try {
                    socketChannel.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
        ;return null;
    }

    @Override
    public String writeData() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "你好,我是客户端";
    }

    @Override
    public void readData(String data) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("客户端读取到数据:"+data);
    }
}

猜你喜欢

转载自blog.csdn.net/wzl1369248650/article/details/82287925