/** * Dianping.com Inc. * Copyright (c) 2003-2013 All Rights Reserved. */ package com.dianping.pigeon.remoting.netty.provider; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.group.ChannelGroup; import org.jboss.netty.channel.group.DefaultChannelGroup; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import com.dianping.pigeon.config.ConfigManagerLoader; import com.dianping.pigeon.remoting.common.domain.Disposable; import com.dianping.pigeon.remoting.common.util.Constants; import com.dianping.pigeon.remoting.provider.AbstractServer; import com.dianping.pigeon.remoting.provider.config.ProviderConfig; import com.dianping.pigeon.remoting.provider.config.ServerConfig; import com.dianping.pigeon.threadpool.NamedThreadFactory; import com.dianping.pigeon.util.NetUtils; public class NettyServer extends AbstractServer implements Disposable { private String ip = null; private int port = ServerConfig.DEFAULT_PORT; private ServerBootstrap bootstrap; private ChannelGroup channelGroup = new DefaultChannelGroup(); private Channel channel; private volatile boolean started = false; private static ExecutorService bossExecutor = Executors.newCachedThreadPool(new NamedThreadFactory( "Pigeon-Netty-Server-Boss", true)); private static ExecutorService workerExecutor = Executors.newCachedThreadPool(new NamedThreadFactory( "Pigeon-Netty-Server-Worker", true)); private static final int workerCount = ConfigManagerLoader.getConfigManager().getIntValue( "pigeon.provider.netty.workercount", Runtime.getRuntime().availableProcessors() * 2); private static ChannelFactory channelFactory = new NioServerSocketChannelFactory(bossExecutor, workerExecutor, workerCount); public NettyServer() { this.bootstrap = new ServerBootstrap(channelFactory); this.bootstrap.setPipelineFactory(new NettyServerPipelineFactory(this)); this.bootstrap.setOption("child.tcpNoDelay", true); this.bootstrap.setOption("child.keepAlive", true); this.bootstrap.setOption("child.reuseAddress", true); this.bootstrap.setOption("child.connectTimeoutMillis", 1000); } @Override public boolean support(ServerConfig serverConfig) { if (serverConfig.getProtocol().equals(this.getProtocol())) { return true; } return false; } @Override public void doStart(ServerConfig serverConfig) { if (!started) { if (serverConfig.isAutoSelectPort()) { int availablePort = getAvailablePort(serverConfig.getPort()); this.port = availablePort; } else { if (NetUtils.isPortInUse(serverConfig.getPort())) { logger.error("unable to start netty server on port " + serverConfig.getPort() + ", the port is in use"); System.exit(0); } this.port = serverConfig.getPort(); } InetSocketAddress address = null; if (this.ip == null) { address = new InetSocketAddress(this.port); } else { address = new InetSocketAddress(this.ip, this.port); } channel = this.bootstrap.bind(address); serverConfig.setActualPort(this.port); this.started = true; } } @Override public void doStop() { if (this.started) { // this.channelGroup.close().awaitUninterruptibly(); // this.bootstrap.releaseExternalResources(); doClose(); this.started = false; } } protected void doClose() { try { if (channelGroup != null) { // unbind. channelGroup.unbind().awaitUninterruptibly(); channelGroup.close().awaitUninterruptibly(); } } catch (Throwable e) { logger.warn(e.getMessage(), e); } if (channel != null) { channel.unbind(); } try { if (bootstrap != null) { // release external resource. bootstrap.releaseExternalResources(); } } catch (Throwable e) { logger.warn(e.getMessage(), e); } try { if (channelGroup != null) { channelGroup.clear(); } } catch (Throwable e) { logger.warn(e.getMessage(), e); } } @Override public void destroy() throws Exception { this.stop(); } public ChannelGroup getChannelGroup() { return channelGroup; } @Override public <T> void doAddService(ProviderConfig<T> providerConfig) { } @Override public <T> void doRemoveService(ProviderConfig<T> providerConfig) { } @Override public String toString() { return "netty server-" + this.port; } @Override public int getPort() { return port; } @Override public String getRegistryUrl(String url) { return url; } public String getRemoteAddress(Channel channel) { InetSocketAddress address = (InetSocketAddress) channel.getRemoteAddress(); return address.getAddress().getHostAddress() + ":" + address.getPort(); } @Override public List<String> getInvokerMetaInfo() { if (channelGroup != null) { List<String> results = new ArrayList<String>(); for (Channel channel : channelGroup) { results.add("from:" + getRemoteAddress(channel) + ",to:" + this.getPort()); } return results; } return null; } @Override public boolean isStarted() { return started; } @Override public String getProtocol() { return Constants.PROTOCOL_DEFAULT; } }