package com.github.wangxuehui.rpc.snrpc.server; import com.github.wangxuehui.rpc.snrpc.conf.SnRpcConfig; import com.github.wangxuehui.rpc.snrpc.serializer.SnRpcRequestDecoder; import com.github.wangxuehui.rpc.snrpc.serializer.SnRpcResponseEncoder; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import java.io.IOException; import java.net.DatagramSocket; import java.net.ServerSocket; import java.util.Map; import com.github.wangxuehui.rpc.snrpc.SnRpcServer; import com.github.wangxuehui.rpc.snrpc.util.HandlerMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author skyim E-mail:wxh64788665@gmail.com * 类说明 */ public class SnNettyRpcServer implements SnRpcServer{ private static final Logger LOGGER = LoggerFactory.getLogger(SnNettyRpcServer.class); private SnRpcConfig snRpcConfig = SnRpcConfig.getInstance(); private Map<String,Object> handlersMap; private int httpListenPort; //传递自定义Handler对象, 加入到handlerMap中: key是接口名称,value是接口的实现类 public SnNettyRpcServer(Object... handlers){ snRpcConfig.loadProperties("snrpcserver.properties"); this.handlersMap = HandlerMapper.getHandlerMap(handlers); } public SnNettyRpcServer(String fileName,Object... handlers){ snRpcConfig.loadProperties(fileName); this.handlersMap = HandlerMapper.getHandlerMap(handlers); } //启动服务器 public void start() throws Throwable { initServerInfo(); initHttpBootstrap(); } private void initServerInfo() { httpListenPort = snRpcConfig.getHttpPort(); //解析XML文件. 在构造服务器的时候,已经将接口和对应的实现类注册到了handlerMap中.为什么还要使用xml解析?? //解析后的结果是将xml中服务名和RpcService对象放入SnNettyRpcServerHandler的serviceMap中. new ParseXmlToService().parse(); } //启动Netty的HTTP服务 private void initHttpBootstrap() throws InterruptedException { if(SnRpcConfig.getInstance().getDevMod()){ StatisticsService.reportPerformance(); } LOGGER.info("init HTTP Bootstrap .........."); EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1) EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); // (2) b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) // (3) .childHandler(new ChannelInitializer<SocketChannel>() { // (4) Handler @Override public void initChannel(SocketChannel ch) throws Exception { //服务端的顺序是从Request解码,Response编码,再到Handler ch.pipeline().addLast(new SnRpcRequestDecoder()); ch.pipeline().addLast(new SnRpcResponseEncoder()); ch.pipeline().addLast(new SnNettyRpcServerHandler(handlersMap)); } }) .option(ChannelOption.SO_BACKLOG, 128) // (5) .childOption(ChannelOption.SO_KEEPALIVE, true); // (6) if(!checkPortConfig(httpListenPort)){ throw new IllegalStateException("port: " + httpListenPort + " already in use"); } // Bind and start to accept incoming connections. ChannelFuture f = b.bind(httpListenPort).sync(); // (7) // Wait until the server socket is closed. // In this example, this does not happen, but you can do that to gracefully // shut down your server. f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } private boolean checkPortConfig(int listenPort) { if(listenPort < 0 || listenPort > 65536){ throw new IllegalArgumentException("Invalid start port: "+listenPort); } ServerSocket ss = null; DatagramSocket ds =null; try { ss = new ServerSocket(listenPort); ss.setReuseAddress(true); ds = new DatagramSocket(listenPort); ds.setReuseAddress(true); return true; }catch(IOException e){ }finally { if(ds!=null){ ds.close(); } if(ss!=null){ try { ss.close(); }catch(IOException e){ } } } return false; } }