All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.litongjava.tio.server.ServerTioConfig Maven / Gradle / Ivy

package com.litongjava.tio.server;

import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Set;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.litongjava.tio.constants.TioCoreConfigKeys;
import com.litongjava.tio.core.ChannelContext;
import com.litongjava.tio.core.ChannelContext.CloseCode;
import com.litongjava.tio.core.Tio;
import com.litongjava.tio.core.TioConfig;
import com.litongjava.tio.core.intf.AioHandler;
import com.litongjava.tio.core.intf.AioListener;
import com.litongjava.tio.core.maintain.GlobalIpBlacklist;
import com.litongjava.tio.core.ssl.SslConfig;
import com.litongjava.tio.server.intf.ServerAioHandler;
import com.litongjava.tio.server.intf.ServerAioListener;
import com.litongjava.tio.utils.AppendJsonConverter;
import com.litongjava.tio.utils.SysConst;
import com.litongjava.tio.utils.SystemTimer;
import com.litongjava.tio.utils.hutool.CollUtil;
import com.litongjava.tio.utils.hutool.StrUtil;
import com.litongjava.tio.utils.lock.SetWithLock;

/**
 * 
 * @author tanyaowu 2016年10月10日 下午5:51:56
 */
public class ServerTioConfig extends TioConfig {
  static Logger log = LoggerFactory.getLogger(ServerTioConfig.class);
  private AcceptCompletionHandler acceptCompletionHandler = null;
  private ServerAioHandler serverAioHandler = null;
  private ServerAioListener serverAioListener = null;
  private Thread checkHeartbeatThread = null;
  private boolean needCheckHeartbeat = true;
  // private static Set SHARED_SET = null;
  private boolean isShared = false;

  public ServerTioConfig(String name) {
    super(name);
  }

  /**
   * 
   * @param keyStoreFile   如果是以"classpath:"开头,则从classpath中查找,否则视为普通的文件路径
   * @param trustStoreFile 如果是以"classpath:"开头,则从classpath中查找,否则视为普通的文件路径
   * @param keyStorePwd
   * @throws FileNotFoundException
   */
  public void useSsl(String keyStoreFile, String trustStoreFile, String keyStorePwd) throws Exception {
    if (StrUtil.isNotBlank(keyStoreFile) && StrUtil.isNotBlank(trustStoreFile)) {
      SslConfig sslConfig = SslConfig.forServer(keyStoreFile, trustStoreFile, keyStorePwd);
      this.setSslConfig(sslConfig);
    }
  }

  /**
   * 
   * @param keyStoreInputStream
   * @param trustStoreInputStream
   * @param passwd
   * @throws Exception
   * @author tanyaowu
   */
  public void useSsl(InputStream keyStoreInputStream, InputStream trustStoreInputStream, String passwd) throws Exception {
    SslConfig sslConfig = SslConfig.forServer(keyStoreInputStream, trustStoreInputStream, passwd);
    this.setSslConfig(sslConfig);
  }

  /**
   * @return the acceptCompletionHandler
   */
  public AcceptCompletionHandler getAcceptCompletionHandler() {
    return acceptCompletionHandler;
  }

  /**
   * @see org.tio.core.TioConfig#getAioHandler()
   *
   * @return
   * @author tanyaowu 2016年12月20日 上午11:34:37
   *
   */
  @Override
  public AioHandler getAioHandler() {
    return this.getServerAioHandler();
  }

  /**
   * @see org.tio.core.TioConfig#getAioListener()
   *
   * @return
   * @author tanyaowu 2016年12月20日 上午11:34:37
   *
   */
  @Override
  public AioListener getAioListener() {
    return getServerAioListener();
  }

  /**
   * @return the serverAioHandler
   */
  public ServerAioHandler getServerAioHandler() {
    return serverAioHandler;
  }

  /**
   * @return the serverAioListener
   */
  public ServerAioListener getServerAioListener() {
    return serverAioListener;
  }

  public void setServerAioListener(ServerAioListener serverAioListener) {
    this.serverAioListener = serverAioListener;
  }

  /**
   * @return
   * @author tanyaowu
   */
  @Override
  public boolean isServer() {
    return true;
  }

  @Override
  public String toString() {
    return "ServerTioConfig [name=" + name + "]";
  }

  public void share(ServerTioConfig tioConfig) {
    synchronized (ServerTioConfig.class) {
      if (tioConfig == this) {
        return;
      }
      this.clientNodes = tioConfig.clientNodes;
      this.connections = tioConfig.connections;
      this.groups = tioConfig.groups;
      this.users = tioConfig.users;
      this.tokens = tioConfig.tokens;
      this.ids = tioConfig.ids;
      this.bsIds = tioConfig.bsIds;
      this.ipBlacklist = tioConfig.ipBlacklist;
      this.ips = tioConfig.ips;

      if (!tioConfig.isShared && !this.isShared) {
        this.needCheckHeartbeat = false;
      }
      if (tioConfig.isShared && !this.isShared) {
        this.needCheckHeartbeat = false;
      }
      if (!tioConfig.isShared && this.isShared) {
        tioConfig.needCheckHeartbeat = false;
      }

      // 下面这两行代码要放到前面if的后面
      tioConfig.isShared = true;
      this.isShared = true;
    }
  }

  public void setServerAioHandler(ServerAioHandler serverAioHandler) {
    this.serverAioHandler = serverAioHandler;
  }

  public void init() {
    super.init();
    this.groupStat = new ServerGroupStat();
    this.acceptCompletionHandler = new AcceptCompletionHandler();
    GlobalIpBlacklist.INSTANCE.init(this);
    Runnable check = new Runnable() {
      @Override
      public void run() {
        // 第一次先休息一下
        try {
          Thread.sleep(1000 * 10);
        } catch (InterruptedException e1) {
          log.error(e1.toString(), e1);
        }

        while (needCheckHeartbeat && !isStopped()) {
          // long sleeptime = heartbeatTimeout;
          if (heartbeatTimeout <= 0) {
            break;
          }
          try {
            Thread.sleep(heartbeatTimeout);
          } catch (InterruptedException e1) {
            log.error(e1.toString(), e1);
          }
          long start = SystemTimer.currTime;
          SetWithLock setWithLock = connections;
          Set set = null;
          long start1 = 0;
          int count = 0;
          ReadLock readLock = setWithLock.readLock();
          readLock.lock();
          try {
            start1 = SystemTimer.currTime;
            set = setWithLock.getObj();

            for (ChannelContext channelContext : set) {
              count++;
              long compareTime = Math.max(channelContext.stat.latestTimeOfReceivedByte, channelContext.stat.latestTimeOfSentPacket);
              long currtime = SystemTimer.currTime;
              long interval = currtime - compareTime;

              boolean needRemove = false;
              if (channelContext.heartbeatTimeout != null && channelContext.heartbeatTimeout > 0) {
                needRemove = interval > channelContext.heartbeatTimeout;
              } else {
                needRemove = interval > heartbeatTimeout;
              }

              if (needRemove) {
                if (!ServerTioConfig.this.serverAioListener.onHeartbeatTimeout(channelContext, interval, channelContext.stat.heartbeatTimeoutCount.incrementAndGet())) {
                  log.info("{}, {} ms or not send and receive message", channelContext, interval);
                  channelContext.setCloseCode(CloseCode.HEARTBEAT_TIMEOUT);
                  Tio.remove(channelContext, interval + " ms not send and receive message");
                }
              }
            }
          } catch (Throwable e) {
            log.error("", e);
          } finally {
            try {
              readLock.unlock();
              if (debug) {
                diagnostic(start, set, start1, count);
              }
            } catch (Throwable e) {
              log.error("", e);
            }
          }
        }
      }
    };

    checkHeartbeatThread = new Thread(check, "tio-timer-checkheartbeat-" + id + "-" + name);
    checkHeartbeatThread.setDaemon(true);
    checkHeartbeatThread.setPriority(Thread.MIN_PRIORITY);
    checkHeartbeatThread.start();
  }

  private void diagnostic(long start, Set set, long start1, int count) {
    StringBuilder builder = new StringBuilder();
    builder.append(SysConst.CRLF).append(name);
    builder.append("\r\n ├ 当前时间:").append(SystemTimer.currTime);
    builder.append("\r\n ├ 连接统计");
    builder.append("\r\n │ \t ├ 共接受过连接数 :").append(((ServerGroupStat) groupStat).accepted.get());
    builder.append("\r\n │ \t ├ 当前连接数 :").append(set.size());
    // builder.append("\r\n │ \t ├ 当前群组数 :").append(groups);
    builder.append("\r\n │ \t ├ 异IP连接数 :").append(this.ips.getIpmap().getObj().size());
    builder.append("\r\n │ \t └ 关闭过的连接数 :").append(groupStat.closed.get());

    builder.append("\r\n ├ 消息统计");
    builder.append("\r\n │ \t ├ 已处理消息 :").append(groupStat.handledPackets.get());
    builder.append("\r\n │ \t ├ 已接收消息(packet/byte) :").append(groupStat.receivedPackets.get()).append("/").append(groupStat.receivedBytes.get());
    builder.append("\r\n │ \t ├ 已发送消息(packet/byte) :").append(groupStat.sentPackets.get()).append("/").append(groupStat.sentBytes.get()).append("b");
    builder.append("\r\n │ \t ├ 平均每次TCP包接收的字节数 :").append(groupStat.getBytesPerTcpReceive());
    builder.append("\r\n │ \t └ 平均每次TCP包接收的业务包 :").append(groupStat.getPacketsPerTcpReceive());
    builder.append("\r\n └ IP统计时段 ");

    if (CollUtil.isNotEmpty(ipStats.durationList)) {
      builder.append("\r\n   \t └ ").append(AppendJsonConverter.convertListLongToJson(this.ipStats.durationList));
    } else {
      builder.append("\r\n   \t └ ").append("没有设置ip统计时间");
    }

    builder.append("\r\n ├ 节点统计");
    builder.append("\r\n │ \t ├ clientNodes :").append(this.clientNodes.getObjWithLock().getObj().size());
    builder.append("\r\n │ \t ├ 所有连接 :").append(this.connections.getObj().size());
    builder.append("\r\n │ \t ├ 绑定user数 :").append(this.users.getMap().getObj().size());
    builder.append("\r\n │ \t ├ 绑定token数 :").append(this.tokens.getMap().getObj().size());
    builder.append("\r\n │ \t └ 等待同步消息响应 :").append(this.waitingResps.getObj().size());

    builder.append("\r\n ├ 群组");
    builder.append("\r\n │ \t └ groupmap:").append(this.groups.getGroupmap().getObj().size());
    builder.append("\r\n └ 拉黑IP ");
    if (this.ipBlacklist != null) {
      builder.append("\r\n   \t └ ").append(AppendJsonConverter.convertCollectionStringToJson(this.ipBlacklist.getAll()));
    }
    builder.append("\r\n └ 正在处理的请求数量: ").append(getCacheFactory().getCache(TioCoreConfigKeys.REQEUST_PROCESSING).keysCollection().size());
    // builder.append("\r\n └ 线程池信息: \n").append(Threads.status());
    log.warn(builder.toString());
    long end = SystemTimer.currTime;
    long iv1 = start1 - start;
    long iv = end - start1;
    log.warn("{}, 检查心跳, 共{}个连接, 取锁耗时{}ms, 循环耗时{}ms, 心跳超时时间:{}ms", name, count, iv1, iv, heartbeatTimeout);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy