package evanq.game.net;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.io.IOException;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
import evanq.game.trace.LogSystem;
import evanq.game.trace.Trace;
//TODO 增加断线重连特性
//TODO 增加关闭通知所有客户端特性
//TODO 增加连接心跳特性
//TODO 增加连接状态管理
/**
*
* 网络服务驱动
*
* @author Evan cppmain@gmail.com
*
*/
public class CopyOfNetServiceAdaptor implements INetService, Runnable {
private Trace logger = LogSystem.getDefaultTrace(CopyOfNetServiceAdaptor.class);
/**
* 以下罗列出此对象的服务状态
*/
private static final byte NET_SERVICE_STATE_IDLE = 1;
private static final byte NET_SERVICE_STATE_OPENING = 2;
private static final byte NET_SERVICE_STATE_OPENED = 3;
private static final byte NET_SERVICE_STATE_CLOSEED = 4;
/**
* 网络IO 服务的类型(客户端,服务器,agent)
*/
protected NetServiceType type;
/**
*
* 连接的类型(用于连接管理器识别)
*/
protected NetConnectionType connectionType;
protected String host;
protected int port;
/**
* the channel of net service
*/
protected Channel channel;
private Thread thread;
private static AtomicInteger threadCounter = new AtomicInteger(1);
//private boolean runInThread=true;//false 的情况调试没有通过,没有阻塞直接运行shutdown代码
private byte state = NET_SERVICE_STATE_IDLE;
private Object stateLock = new Object();
//close listener
protected LinkedList<IChannelDisposeListener> closeListeners = new LinkedList<IChannelDisposeListener>();
//start listener
protected LinkedList<IChannelCreateListener> startListeners = new LinkedList<IChannelCreateListener>();
/**
*
* 服务初始化工具,能够根据连接的类型,分配不同的编码、解码器
*
* @see DefaultNettyInitializer
*/
protected AbstractNettyChannelInitializer nettyInitializer;
private INetServiceHandler netServiceHandler;
/**
* @param serviceType
* @param port
* @param handler
*/
public CopyOfNetServiceAdaptor(NetServiceType serviceType,int port, INetServiceHandler handler){
this(serviceType,null,port,handler,null);
}
/**
*
* @param serviceType
* @param host
* @param port
* @param handler
*/
public CopyOfNetServiceAdaptor(NetServiceType serviceType,String host, int port, INetServiceHandler handler) {
this(serviceType,host,port,handler,null);
}
/**
*
* @param serviceType
* @param host
* @param port
* @param handler
*/
public CopyOfNetServiceAdaptor(NetServiceType serviceType,String host, int port, INetServiceHandler handler,AbstractNettyChannelInitializer nettyInitializer){
if (port < 1024 || port > 63365) {
throw new IllegalArgumentException("端口控制在1024-63365之间");
}
if (null == host) {
if (type != NetServiceType.CLIENT) {
host = "0.0.0.0";
} else {
throw new NullPointerException("host");
}
}
connectionType = NetConnectionType.DUMMY;
if(null == handler){
throw new NullPointerException("handler");
}
this.netServiceHandler = handler;
if (null == nettyInitializer) {
nettyInitializer = newNettyInitializer();
}
this.nettyInitializer = nettyInitializer;
this.type = serviceType;
this.host = host;
this.port = port;
thread = new Thread(this,""+type +"-"+threadCounter.getAndIncrement());
}
protected AbstractNettyChannelInitializer newNettyInitializer(){
return new DefaultNettyInitializer(this.netServiceHandler);
}
@Override
public void run() {
synchronized (stateLock) {
state = NET_SERVICE_STATE_OPENED;
}
switch (type) {
case CLIENT:
openClientConnect0();
break;
case SERVER:
case AGENT_SERVER:
case AGENT_CLIENT:
openServer0();
break;
}
synchronized (stateLock) {
state = NET_SERVICE_STATE_IDLE;
}
}
public void open() {
if(state == NET_SERVICE_STATE_OPENING ){
throw new IllegalMonitorStateException("重复开启");
}
synchronized (stateLock) {
if (state == NET_SERVICE_STATE_IDLE) {
state = NET_SERVICE_STATE_OPENING;
thread.start();
}
}
}
public boolean isOpen(){
return state == NET_SERVICE_STATE_OPENED;
}
private void openServer0() {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
try{
netServiceHandler.fireWillStartNetService();
ServerBootstrap boot = new ServerBootstrap();
boot.group(bossGroup, workGroup)
.channel(NioServerSocketChannel.class)
.childHandler(nettyInitializer);
ChannelFuture bindFuture = boot.bind(this.port );
bindFuture.awaitUninterruptibly();
if ( bindFuture.isCancelled() ) {
// Connection attempt cancelled by user
} else if (!bindFuture.isSuccess()) {
logger.info("{} listen at {}:{} Failed",type,host,port);
bindFuture.cause().printStackTrace();
} else {
channel = bindFuture.channel();
logger.info("{} listen at {}:{}",type,host,port);
for (IChannelCreateListener l : startListeners) {
l.onCreate(CopyOfNetServiceAdaptor.this.channel);
}
netServiceHandler.fireDidStartNetService();
channel.closeFuture().awaitUninterruptibly();
netServiceHandler.fireWillCloseNetService();
logger.info("{} for {}:{} closing!",type,host,port);
for (IChannelDisposeListener l : closeListeners) {
l.onDispose(CopyOfNetServiceAdaptor.this.channel);
}
}
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
startListeners.clear();
closeListeners.clear();
}
}
private synchronized void openClientConnect0(){
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group).handler(nettyInitializer)
.channel(NioSocketChannel.class);
netServiceHandler.fireWillStartNetService();
//TODO 控制客户端断线重连,配置信息
boolean willRetry= false;
int delayRetryTime = 5000;
try{
do{
boolean donotRetry = openClientConnect0(b);
if( ! donotRetry ) {
awaitForRetry(delayRetryTime);
willRetry = true;
continue;
}
synchronized (stateLock) {
state = NET_SERVICE_STATE_OPENED;
}
netServiceHandler.fireDidStartNetService();
//try 防止正常运行,服务器断开,这时候重连
try {
openClientConnect1();
} catch (IOException e) {
awaitForRetry(delayRetryTime);
willRetry = true;
continue;
}
willRetry = false;
}while(willRetry);
}finally{
group.shutdownGracefully();
startListeners.clear();
closeListeners.clear();
}
}
/**
* 绑定客户端连接关闭完成事件
*/
private void openClientConnect1() throws IOException {
if(null == channel)return ;
channel.closeFuture().awaitUninterruptibly();
if(state == NET_SERVICE_STATE_CLOSEED){
//属于正常断开
logger.info("{} to {}:{} closing!",type,host,port);
if(null == connectionType){
logger.warn("connectionType is null when create connection");
}
for (IChannelDisposeListener l : closeListeners) {
l.onDispose(CopyOfNetServiceAdaptor.this.channel);
}
netServiceHandler.fireDidCloseNetService();
}else{
synchronized (stateLock) {
state = NET_SERVICE_STATE_CLOSEED;
}
throw new IOException("非正常断开");
}
}
/**
* 开始连接,成功会时候channel !=null
* return true do not retry.
*/
private boolean openClientConnect0(Bootstrap b) {
ChannelFuture connectFutrue = b.connect(host, port);
//阻塞等待连接完成
connectFutrue.awaitUninterruptibly();
if ( connectFutrue.isCancelled() ) {
// Connection attempt cancelled by user
return true;
} else if (!connectFutrue.isSuccess()) {
logger.warn("{} connect to {}:{} Failed",type,host,port);
return false;
//connectFutrue.cause().printStackTrace();
} else {
channel = connectFutrue.channel();
//需要服务器验证之后,才会根据connectionType 设定编解码器
AbstractNettyChannelInitializer.setChannelType(channel, connectionType);
logger.info("{} connect to {}:{} Success",type,host,port);
for (IChannelCreateListener l : startListeners) {
l.onCreate(CopyOfNetServiceAdaptor.this.channel);
}
return true;
}
}
private void awaitForRetry(int delayRetryTime){
logger.info("{} delay {}ms,than Retry connect {}:{}",type,delayRetryTime,host,port);
try {
wait(delayRetryTime);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
public void close() {
synchronized (stateLock) {
if (null != channel ) {
channel.close();
}
state = NET_SERVICE_STATE_CLOSEED;
}
}
public void addChannelCreateListener(IChannelCreateListener startListener){
if(NET_SERVICE_STATE_OPENED <= state){
throw new IllegalAccessError("必须open() 之前注册startListener");
}
if (null == startListener) {
throw new NullPointerException("startListener");
}
this.startListeners.add(startListener);
}
public void addChannelDisposeListener(IChannelDisposeListener closeListener){
if (null == closeListener) {
throw new NullPointerException("closeListener");
}
this.closeListeners.add(closeListener);;
}
@Override
public NetServiceType serviceTye() {
return type;
}
@Override
public NetConnectionType connectionType() {
return connectionType;
}
public NetConnectionType connectionType(NetConnectionType connectionType) {
this.connectionType = connectionType;
return this.connectionType;
}
}