package com.dianping.puma.pumaserver.server;
import com.dianping.cat.Cat;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.apache.commons.lang3.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Dozer @ 11/21/14
* mail@dozer.cc
* http://www.dozer.cc
*/
public final class TcpServer {
private static Logger logger = LoggerFactory.getLogger(TcpServer.class);
private static final boolean needToUseEpoll = SystemUtils.IS_OS_LINUX;
private volatile EventLoopGroup bossGroup;
private volatile EventLoopGroup workerGroup;
private volatile ServerBootstrap bootstrap;
private final ServerConfig config;
private volatile boolean closed = false;
public TcpServer(ServerConfig config) {
this.config = config;
}
public void close() {
closed = true;
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
logger.info("Stopped Tcp Server: " + config.getPort());
Cat.logEvent("Server.Stop", "Tcp: " + config.getPort());
}
public void init() {
if (closed) {
return;
}
bossGroup = needToUseEpoll ? new EpollEventLoopGroup() : new NioEventLoopGroup();
workerGroup = needToUseEpoll ? new EpollEventLoopGroup() : new NioEventLoopGroup();
bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup);
bootstrap.channel(needToUseEpoll ? EpollServerSocketChannel.class : NioServerSocketChannel.class);
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
Map<String, ChannelHandler> handlers = config.getHandlerFactory().getHandlers();
for (Map.Entry<String, ChannelHandler> entry : handlers.entrySet()) {
pipeline.addLast(entry.getKey(), entry.getValue());
}
}
});
bootstrap.childOption(ChannelOption.SO_REUSEADDR, true);
bootstrap.childOption(ChannelOption.TCP_NODELAY, true);
bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
bootstrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
doBind();
}
protected void doBind() {
if (closed) {
return;
}
bootstrap.bind(config.getPort()).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture f) throws Exception {
if (f.isSuccess()) {
logger.info("Started Tcp Server: " + config.getPort());
Cat.logEvent("Server.Started", "Tcp: " + config.getPort());
} else {
String msg = "Started Tcp Server Failed: " + config.getPort();
logger.error(msg, f.cause());
Cat.logError(msg, f.cause());
f.channel().eventLoop().schedule(new Runnable() {
@Override
public void run() {
doBind();
}
}, 5, TimeUnit.SECONDS);
}
}
});
}
}