Package com.firefly.net.tcp

Source Code of com.firefly.net.tcp.TcpServer$Boss

package com.firefly.net.tcp;

import com.firefly.net.*;
import com.firefly.net.exception.NetException;
import com.firefly.utils.log.Log;
import com.firefly.utils.log.LogFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.*;

public class TcpServer implements Server {

  private static Log log = LogFactory.getInstance().getLog("firefly-system");
    private Config config;
    private Worker[] workers;
    private Thread bossThread;
    private boolean start;

    public TcpServer() {

    }

    public TcpServer(Decoder decoder, Encoder encoder,
                     Handler handler) {
        config = new Config();
        config.setDecoder(decoder);
        config.setEncoder(encoder);
        config.setHandler(handler);
    }

    @Override
    public void setConfig(Config config) {
        this.config = config;
    }

    @Override
    public void start(String host, int port) {
        if (config == null)
            throw new NetException("server config is null");
        log.debug(config.toString());
        listen(bind(host, port));
    }

    private ServerSocketChannel bind(String host, int port) {
        ServerSocketChannel serverSocketChannel = null;
        try {
            serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.socket().setReuseAddress(true);
            serverSocketChannel.socket().setPerformancePreferences(
                    config.getConnectionTime(), config.getLatency(),
                    config.getBandwidth());
            log.debug("ServerSocket receiveBufferSize: [{}]",
                    serverSocketChannel.socket().getReceiveBufferSize());
            if (config.getReceiveBufferSize() > 0)
                serverSocketChannel.socket().setReceiveBufferSize(
                        config.getReceiveBufferSize());
            serverSocketChannel.socket().bind(
                    new InetSocketAddress(host, port),
                    config.getBacklog());

        } catch (Exception e) {
            log.error("ServerSocket bind error", e);
        }
        return serverSocketChannel;
    }

    private void listen(ServerSocketChannel serverSocketChannel) {
        workers = new Worker[config.getWorkerThreads()];
        for (int i = 0; i < config.getWorkerThreads(); i++) {
            workers[i] = new TcpWorker(config, i, null);
        }

        Boss boss = null;
        try {
            boss = new Boss(serverSocketChannel);
        } catch (IOException e) {
            log.error("Boss create error", e);
        }
        bossThread = new Thread(boss, config.getServerName());
        start = true;
        bossThread.start();
    }

    private final class Boss implements Runnable {
        private final Selector selector;
        private final ServerSocketChannel serverSocketChannel;

        public Boss(ServerSocketChannel serverSocketChannel) throws IOException {
            selector = Selector.open();
            this.serverSocketChannel = serverSocketChannel;
            this.serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        }

        @Override
        public void run() {

            int sessionId = 0;
            try {
                while (start) {
                    try {
                        if (selector.select(1000) > 0)
                            selector.selectedKeys().clear();

                        SocketChannel socketChannel = serverSocketChannel
                                .accept();
                        if (socketChannel != null) {
                            accept(socketChannel, sessionId);
                            sessionId++;
                        }
                    } catch (ClosedChannelException e) {
                        // Closed as requested.
                        break;
                    } catch (Throwable e) {
                        log.error("Failed to accept a connection.", e);
                    }
                }
            } finally {
                try {
                    selector.close();
                } catch (Exception e) {
                    log.error("Failed to close a selector.", e);
                }
            }

        }

        public void accept(SocketChannel socketChannel, int sessionId) {
            try {
                int workerIndex = Math.abs(sessionId) % workers.length;
                log.debug("accept sessionId [{}] and worker index [{}]",
                        sessionId, workerIndex);
                workers[workerIndex].registerSelectableChannel(socketChannel,
                        sessionId);
            } catch (Exception e) {
                log.error("Failed to initialize an accepted socket.", e);
                try {
                    socketChannel.close();
                } catch (IOException e1) {
                    log.error("Failed to close a partially accepted socket.",
                            e1);
                }
            }
        }

    }

  @Override
  public void shutdown() {
    for(Worker worker : workers) {
      worker.shutdown();
    }
    start = false;
    log.debug("thread {} is shutdown: {}", bossThread.getName(), bossThread.isInterrupted());
  }

}
TOP

Related Classes of com.firefly.net.tcp.TcpServer$Boss

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.