All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hotwheel.asio.Asio Maven / Gradle / Ivy

There is a newer version: 5.6.9
Show newest version
package org.hotwheel.asio;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.io.IOException;
import java.net.Socket;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

/**
 * 异步网络接口
 *
 * @author wangfeng
 * @since 2016年1月9日 下午5:10:39
 */
public abstract class Asio extends AioBenchmark
        implements AioHandler, Closeable, CompletionHandler {
    protected Logger logger = LoggerFactory.getLogger(getClass());
    public final static int AE_ACCEPT = SelectionKey.OP_ACCEPT;
    public final static int AE_CONNECT = SelectionKey.OP_CONNECT;
    public final static int AE_READ = SelectionKey.OP_READ;
    public final static int AE_WRITE = SelectionKey.OP_WRITE;
    private AioHandler handler = null;
    protected final static int kBufferSize = 512 * 1024;
    protected ScoreBoard scoreBoard = new ScoreBoard();
    protected boolean debug = false;

    /**
     * 选择器
     */
    protected Selector selector = null;
    /**
     * 是否运行
     */
    protected boolean done = false;

    public Asio(int number, int concurrency) throws IOException{
        super(number, concurrency);
        selector = Selector.open();
        scoreBoard.number = number;
    }

    public Selector getSelector() {
        return selector;
    }

    @Override
    public void close() {
        try {
            selector.close();
        } catch (IOException e) {
            logger.error("Selector close failed: ", e);
        }
    }

    /**
     * socket是否关闭
     *
     * @param sc
     * @return
     */
    public boolean isClosed(SocketChannel sc) {
        boolean bRet = true;
        if (sc != null) {
            Socket socket = sc.socket();
            if (socket != null) {
                bRet = socket.isClosed();
            }
        }
        return bRet;
    }

    /**
     * 更新计时
     *
     * @param context
     */
    private void updateTime(T context) {
        context.setStartTime(System.currentTimeMillis());
    }

    protected SelectionKey keyFor(SocketChannel sc) {
        SelectionKey key = sc.keyFor(selector);
        return key;
    }

    @SuppressWarnings("unchecked")
    protected T contextFor(SelectionKey key) {
        return (T) key.attachment();
    }

    protected T contextFor(SocketChannel sc) {
        SelectionKey sk = keyFor(sc);
        return contextFor(sk);
    }

    protected SocketChannel createSocket() throws IOException {
        SocketChannel sc = null;
        sc = SocketChannel.open();
        sc.configureBlocking(false);
        //sc.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
        sc.setOption(StandardSocketOptions.SO_REUSEADDR, true);
        //sc.socket().setSoTimeout(10 * 1000);
        sc.setOption(StandardSocketOptions.TCP_NODELAY, true);
        // SO_LINGGER参数在java不能使用,
        //System.out.println("SO_LINGER:" + sc.getOption(StandardSocketOptions.SO_LINGER));
        sc.setOption(StandardSocketOptions.SO_LINGER, 0);
        //socket.setSoTimeout(connectTimeout);
        sc.setOption(StandardSocketOptions.SO_RCVBUF, kBufferSize);
        sc.setOption(StandardSocketOptions.SO_SNDBUF, kBufferSize);

        return sc;
    }

    /**
     * 关闭网络通道
     *
     * @param sc
     */
    protected void closeChannel(SocketChannel sc) {
        try {
            SelectionKey key = keyFor(sc);
            if (key != null) {
                key.cancel();
            }
            sc.shutdownOutput();
            if (sc.isConnected()) {
                ByteBuffer buff = ByteBuffer.allocate(4096);
                int recviced = 0;
                while ((recviced = sc.read(buff)) != -1) {
                    if (debug) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("recviced:" + recviced);
                        }
                    }
                }
                sc.shutdownInput();
                sc.close();
            }
        } catch (Exception e) {
            //logger.error("SocketChannel close failed: ", e);
        } finally {
            //
        }
    }

    @Override
    public void handleCompact(Selector selector) {
        onCompact(null);
    }

    @Override
    public void handleAccepted(SocketChannel sc) {
        T context = contextFor(sc);
        onAccepted(context);
    }

    /**
     * channel关闭处理
     *
     * @param sc
     */
    @Override
    public void handleClosed(SocketChannel sc) {
        T context = contextFor(sc);
        onClosed(context);
        closeChannel(sc);
    }

    @Override
    public void handleError(SocketChannel sc, Exception e) {
        T context = contextFor(sc);
        onError(context, e);
        handleClosed(sc);
    }

    /**
     * 超时处理, 随后调用关闭channel方法
     *
     * @param sc
     */
    @Override
    public void handleTimeout(SocketChannel sc) {
        onTimeout(contextFor(sc));
        handleClosed(sc);
    }

    @Override
    public void handleConnected(SocketChannel sc) {
        SelectionKey sk = keyFor(sc);
        T context = contextFor(sc);
        // 如果客户端没有立即连接到服务端, 则客户端完成非立即连接操作
        try {
            // 设置成非阻塞
            //sc.configureBlocking(false);
            //if (sc.finishConnect()) {
                // 处理完后必须吧OP_CONNECT关注去掉, 改为关注OP_READ
                onConnected(context);
                //if (!isClosed(sc)) {
                    sk.interestOps(SelectionKey.OP_READ);
                //}
            //} else {
            //    handleError(sc);
            //}
        } /*catch (ConnectException e) {
            // java.net.ConnectException: Operation timed out
            handleTimeout(sc);
        } catch (IOException e) {
            handleError(sc);
        }*/ catch (Exception e) {
            handleError(sc, e);
        }
    }

    /**
     * channel读数据
     *
     * @param sc
     */
    @Override
    public void handleRead(SocketChannel sc) {
        SelectionKey sk = keyFor(sc);
        T context = contextFor(sc);
        int bufferLen = kBufferSize;
        //bufferLen = 1;
        ByteBuffer buf = ByteBuffer.allocate(bufferLen);
        long bytesRead = 0;
        try {
            //sc.socket().getInetAddress()
            bytesRead = sc.read(buf);
            //T ctx = contextFor(sc);
            if (bytesRead == -1) { // Did the other end close?
                //onRead(ctx);
                //onCompleted(context);
                handleError(sc, new NotYetConnectedException());
            } else {
                context.add((ByteBuffer) buf.flip());
                onRead(context);
                if(bytesRead >= bufferLen) {
                    //sk.interestOps(SelectionKey.OP_READ);
                } else {
                    //
                }
                if(context != null && context.completed()){
                    onCompleted(context);
                    handleClosed(sc);
                } else {
                    //sk.interestOps(SelectionKey.OP_READ);
                }
            }
        } catch (Exception e) {
            logger.error("read error: ", e);
            handleError(sc, e);
        }
    }

    @Override
    public void handleWrite(SocketChannel sc) {
        SelectionKey sk = keyFor(sc);
        T context = contextFor(sc);
        onWrite(context);
    }

    /**
     * 检测所有在册的通道超时情况, 并处理
     */
    private void checkTimeout() {
        Iterator it = selector.keys().iterator();
        while (it.hasNext()) {
            SelectionKey sk = (SelectionKey) it.next();
            SocketChannel sc = (SocketChannel) sk.channel();
            T context = contextFor(sk);
            if (context.isTimeout()) {
                handleTimeout(sc);
            }
        }

    }

    /**
     * 网络事件监控主流程
     *
     * @return
     */
    public int start() {
        int iRet = -1;

        int num = 0;
        done = true;
        // 主流程不允许抛出异常
        while (done) {
            try {
                // 超时检测
                num = selector.select(/*timeout*/1);
                //num = selector.selectNow();
                if (num < 1) {
                    // 全部超时
                    checkTimeout();
                } else {
                    // 遍历每个有可用IO操作Channel对应的SelectionKey
                    Iterator it = selector.selectedKeys().iterator();
                    while (it.hasNext()) {
                        final SelectionKey sk = (SelectionKey) it.next();
                        int ops = sk.readyOps();
                        boolean isAcceptable = (ops & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT;
                        boolean isConnectable = (ops & SelectionKey.OP_CONNECT) == SelectionKey.OP_CONNECT;
                        boolean isReadable = (ops & SelectionKey.OP_READ) == SelectionKey.OP_READ;
                        boolean isWritable = (ops & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE;
                        T context = contextFor(sk);
                        // 从集合中删除此次事件
                        it.remove();
                        SocketChannel channel = (SocketChannel) sk.channel();
                        if (isAcceptable) {
                            // 新客户端连接到达
                            ServerSocketChannel ssc = (ServerSocketChannel) sk.channel();
                            channel = ssc.accept();
                            // 将客户端套接字通过连接模式调整为非阻塞模式
                            channel.configureBlocking(false);
                            // 将客户端套接字通道OP_READ事件注册到通道选择器上
                            channel.register(selector, SelectionKey.OP_READ, null);
                            handleAccepted(channel);
                        } /*else if (sk.isConnectable() && !channel.isConnected()) {
                            // 当前通道选择器产生连接已经准备就绪事件, 并且客户端套接字
                            // 通道尚未连接到服务端套接字通道
                            handleConnected(channel);
                        }*/else if (isConnectable) {
                            boolean bError = false;
                            //如果正在连接,则完成连接
                            if(channel.isConnectionPending()){
                                try {
                                    channel.finishConnect();
                                } catch (Exception e) {
                                    bError = true;
                                    handleError(channel, e);
                                }
                            }
                            if (!bError) {
                                handleConnected(channel);
                            }
                        }
                        else if (isReadable) {
                            // 有数据可读, 读取数据字节数小于1, 即客户端断开, 需要关闭socket通道
                            handleRead(channel);
                        } else if (isWritable) {
                            // socket通道可写
                            handleWrite(channel);
                        } else {
                            // 一般情况下不太可能到达这个位置
                            //System.out.print('P');
                            handleError(channel, new Exception("未知异常"));
                        }
                        // 更新时间
                        if (context != null) {
                            updateTime(context);
                        }
                    }
                    //
                }
                handleCompact(selector);
            } catch (Exception e) {
                logger.error("Selector.select failed: ", e);
            } finally {
                //
            }
        }
        return iRet;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy