package com.snowcattle.game.service.rpc.client.net;
import com.snowcattle.game.common.constant.Loggers;
import com.snowcattle.game.service.net.RpcRequest;
import com.snowcattle.game.service.rpc.server.RpcNodeInfo;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by jiangwenping on 17/3/14.
* 管理连接
*/
public class RpcClientConnection {
private Logger logger = Loggers.rpcLogger;
private NioSocketChannel channel;
private ReentrantLock statusLock;
/**
* 重连线程池工具
*/
private ExecutorService threadPool;
EventLoopGroup eventLoopGroup = new NioEventLoopGroup(1);
// /**
// * 重连标识 因为重连的时候没有加锁,会导致检查链接失败,丢失包信息
// */
// private volatile boolean reConnect = false;
/**
* 是否启用重连
*/
private volatile boolean reConnectOn = true;
private RpcClient rpcClient;
private RpcNodeInfo rpcNodeInfo;
public RpcClientConnection(RpcClient rpcClient, RpcNodeInfo rpcNodeInfo, ExecutorService threadPool) {
if (threadPool == null) {
throw new IllegalArgumentException("All parameters must accurate.");
}
this.rpcClient = rpcClient;
this.rpcNodeInfo = rpcNodeInfo;
this.threadPool = threadPool;
this.statusLock = new ReentrantLock();
}
/**
* 创建打开连接
*
* @return
*/
public boolean open() {
// 判断是否已经连接
if (isConnected()) {
throw new IllegalStateException("Already connected. Disconnect first.");
}
// 创建Socket连接
try {
InetSocketAddress remotePeer = new InetSocketAddress(rpcNodeInfo.getHost(), rpcNodeInfo.getIntPort());
//连接结束
logger.debug("connect to remote server. remote peer = " + remotePeer);
Future future = threadPool.submit(new RpcServerConnectTask(rpcNodeInfo, eventLoopGroup, rpcClient));
future.get();
if(isConnected()){
return false;
}
if (logger.isInfoEnabled()) {
logger.info("Connect success.");
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
//是否连接
public boolean isConnected(){
if(channel == null){
return false;
}
return channel.isActive();
}
/**
* 发送一条消息
*
* @param message
* @return
*/
public boolean writeRequest(RpcRequest rpcRequest) {
if (!isConnected() && reConnectOn) {
// 是否正在重连中
// if (!reConnect) {
// 重新连接
tryReConnect();
// }
//依然链接不上,返回false
if (!isConnected()) {
return false;
}
}
// 发送消息
if (channel != null) {
if (logger.isDebugEnabled()) {
logger.debug("【Send】" + rpcRequest);
}
channel.writeAndFlush(rpcRequest);
return true;
}
return false;
}
public void tryReConnect() {
statusLock.lock(); // block until condition holds
try {
if(!isConnected()) {
// reConnect = true;
try {
//强制链接,进行等待
Future<?> future = threadPool.submit(new ReConnect());
future.get();
} catch (Exception e) {
// reConnect = false;
}
}
} catch (Exception e) {
// reConnect = false;
}finally {
statusLock.unlock();
}
}
/**
* 重连线程内部类
*
* @author Fancy
*/
private class ReConnect implements Runnable {
public void run() {
try {
open();
} catch (Exception e) {
if (logger.isErrorEnabled()) {
logger.error("Restart connection error.");
}
} finally {
// 设置为允许重连
// reConnect = false;
}
}
}
/**
* 启动自动重连
*/
public void setReconnectOn() {
this.reConnectOn = true;
}
/**
* 关闭自动重连
*/
public void setReconnectOff() {
this.reConnectOn = false;
}
public NioSocketChannel getChannel() {
return channel;
}
public void setChannel(NioSocketChannel channel) {
this.channel = channel;
}
public void close(){
if(channel != null) {
channel.close();
}
eventLoopGroup.shutdownGracefully();
}
}