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

com.litongjava.tio.core.ChannelContext Maven / Gradle / Ivy

There is a newer version: 3.7.3.v20241201-RELEASE
Show newest version
package com.litongjava.tio.core;

import java.io.IOException;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.HashSet;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;

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

import com.litongjava.tio.core.intf.Packet;
import com.litongjava.tio.core.intf.Packet.Meta;
import com.litongjava.tio.core.ssl.SslFacadeContext;
import com.litongjava.tio.core.stat.ChannelStat;
import com.litongjava.tio.core.stat.IpStat;
import com.litongjava.tio.core.task.DecodeRunnable;
import com.litongjava.tio.core.task.HandlerRunnable;
import com.litongjava.tio.core.task.SendRunnable;
import com.litongjava.tio.utils.Threads;
import com.litongjava.tio.utils.hutool.CollUtil;
import com.litongjava.tio.utils.hutool.StrUtil;
import com.litongjava.tio.utils.lock.SetWithLock;
import com.litongjava.tio.utils.prop.MapWithLockPropSupport;

/**
 *
 * @author tanyaowu 2017年10月19日 上午9:39:46
 */
public abstract class ChannelContext extends MapWithLockPropSupport {
  private static Logger log = LoggerFactory.getLogger(ChannelContext.class);
  private static final String DEFAULT_ATTUBITE_KEY = "t-io-d-a-k";
  public static final String UNKNOWN_ADDRESS_IP = "$UNKNOWN";
  public static final AtomicInteger UNKNOWN_ADDRESS_PORT_SEQ = new AtomicInteger();
  public boolean isReconnect = false;
  /**
   * 解码出现异常时,是否打印异常日志 此值默认与org.tio.core.TioConfig.logWhenDecodeError保持一致
   */
  public boolean logWhenDecodeError = false;
  /**
   * 此值不设时,心跳时间取org.tio.core.TioConfig.heartbeatTimeout
   * 当然这个值如果小于org.tio.core.TioConfig.heartbeatTimeout,定时检查的时间间隔还是以org.tio.core.TioConfig.heartbeatTimeout为准,只是在判断时用此值
   */
  public Long heartbeatTimeout = null;
  /**
   * 一个packet所需要的字节数(用于应用告诉框架,下一次解码所需要的字节长度,省去冗余解码带来的性能损耗)
   */
  public Integer packetNeededLength = null;
  public TioConfig tioConfig = null;
  public DecodeRunnable decodeRunnable = null;
  public HandlerRunnable handlerRunnable = null;
  public SendRunnable sendRunnable = null;
  public final ReentrantReadWriteLock closeLock = new ReentrantReadWriteLock();
  private ReadCompletionHandler readCompletionHandler = null; // new ReadCompletionHandler(this);
  public WriteCompletionHandler writeCompletionHandler = null; // new WriteCompletionHandler(this);
  public SslFacadeContext sslFacadeContext;
  public String userid;
  private String token;
  private String bsId;
  public boolean isWaitingClose = false;
  public boolean isClosed = true;
  public boolean isRemoved = false;
  public boolean isVirtual = false;
  public boolean hasTempDir = false;
  public final ChannelStat stat = new ChannelStat();
  /** The asynchronous socket channel. */
  public AsynchronousSocketChannel asynchronousSocketChannel;
  private String id = null;
  private Node clientNode;
  private Node proxyClientNode = null; // 一些连接是代理的,譬如web服务器放在nginx后面,此时需要知道最原始的ip
  private Node serverNode;
  /**
   * 该连接在哪些组中
   */
  private SetWithLock groups = null;
  private Integer readBufferSize = null; // 个性化readBufferSize
  public CloseMeta closeMeta = new CloseMeta();
  private CloseCode closeCode = CloseCode.INIT_STATUS; // 连接关闭的原因码

  /**
   *
   * @param tioConfig
   * @param asynchronousSocketChannel
   * @author tanyaowu
   */
  public ChannelContext(TioConfig tioConfig, AsynchronousSocketChannel asynchronousSocketChannel) {
    super();
    init(tioConfig, asynchronousSocketChannel);

    if (tioConfig.sslConfig != null) {
      try {
        SslFacadeContext sslFacadeContext = new SslFacadeContext(this);
        if (tioConfig.isServer()) {
          sslFacadeContext.beginHandshake();
        }
      } catch (Exception e) {
        log.error("在开始SSL握手时发生了异常", e);
        Tio.close(this, "在开始SSL握手时发生了异常" + e.getMessage(), CloseCode.SSL_ERROR_ON_HANDSHAKE);
        return;
      }
    }
  }

  /**
   * 创建一个虚拟ChannelContext,主要用来模拟一些操作,譬如压力测试,真实场景中用得少
   * 
   * @param tioConfig
   */
  public ChannelContext(TioConfig tioConfig) {
    this(tioConfig, tioConfig.getTioUuid().uuid());
  }

  /**
   * 创建一个虚拟ChannelContext,主要用来模拟一些操作,譬如压力测试,真实场景中用得少
   * 
   * @param tioConfig
   * @param id        ChannelContext id
   * @author tanyaowu
   */
  public ChannelContext(TioConfig tioConfig, String id) {
    isVirtual = true;
    this.tioConfig = tioConfig;
    Node clientNode = new Node("127.0.0.1", 26254);
    this.clientNode = clientNode;
    this.id = id;// tioConfig.getTioUuid().uuid();
    if (StrUtil.isBlank(id)) {
      this.id = tioConfig.getTioUuid().uuid();
    }

    initOther();
  }

  private void assignAnUnknownClientNode() {
    Node clientNode = new Node(UNKNOWN_ADDRESS_IP, UNKNOWN_ADDRESS_PORT_SEQ.incrementAndGet());
    setClientNode(clientNode);
  }

  /**
   * 创建Node
   * 
   * @param asynchronousSocketChannel
   * @return
   * @throws IOException
   * @author tanyaowu
   */
  public abstract Node createClientNode(AsynchronousSocketChannel asynchronousSocketChannel) throws IOException;

  /**
   *
   * @param obj
   * @return
   * @author tanyaowu
   */
  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null) {
      return false;
    }
    if (getClass() != obj.getClass()) {
      return false;
    }
    ChannelContext other = (ChannelContext) obj;
    if (id == null) {
      if (other.id != null)
        return false;
    } else if (!id.equals(other.id)) {
      return false;
    }
    return true;
  }

  /**
   * 等价于:getAttribute(DEFAULT_ATTUBITE_KEY)
   * 
   * @deprecated 建议使用get()
   * @return
   */
  public Object getAttribute() {
    return get();
  }

  /**
   * 等价于:getAttribute(DEFAULT_ATTUBITE_KEY)
* 等价于:getAttribute()
* * @return */ public Object get() { return get(DEFAULT_ATTUBITE_KEY); } /** * @return the remoteNode */ public Node getClientNode() { return clientNode; } public SetWithLock getGroups() { return groups; } /** * @return the id */ public String getId() { return id; } /** * @return the readCompletionHandler */ public ReadCompletionHandler getReadCompletionHandler() { return readCompletionHandler; } /** * @return the serverNode */ public Node getServerNode() { return serverNode; } public String getToken() { return token; } /** * @return the writeCompletionHandler */ public WriteCompletionHandler getWriteCompletionHandler() { return writeCompletionHandler; } /** * * @return * @author tanyaowu */ @Override public int hashCode() { if (StrUtil.isNotBlank(id)) { return this.id.hashCode(); } else { return super.hashCode(); } } public void init(TioConfig tioConfig, AsynchronousSocketChannel asynchronousSocketChannel) { id = tioConfig.getTioUuid().uuid(); this.setTioConfig(tioConfig); tioConfig.ids.bind(this); this.setAsynchronousSocketChannel(asynchronousSocketChannel); this.readCompletionHandler = new ReadCompletionHandler(this); this.writeCompletionHandler = new WriteCompletionHandler(this); this.logWhenDecodeError = tioConfig.logWhenDecodeError; initOther(); } void initOther() { if (!tioConfig.isShortConnection) { // 在长连接中,绑定群组几乎是必须要干的事,所以直接在初始化时给它赋值,省得在后面做同步处理 groups = new SetWithLock(new HashSet<>()); } } /** * * @param packet * @param isSentSuccess * @author tanyaowu */ public void processAfterSent(Packet packet, Boolean isSentSuccess) { isSentSuccess = isSentSuccess == null ? false : isSentSuccess; Meta meta = packet.getMeta(); if (meta != null) { CountDownLatch countDownLatch = meta.getCountDownLatch(); // traceBlockPacket(SynPacketAction.BEFORE_DOWN, packet, countDownLatch, null); countDownLatch.countDown(); } try { if (log.isDebugEnabled()) { log.debug("{} Sent {}", this, packet.logstr()); } // 非SSL or SSL已经握手 if (this.sslFacadeContext == null || this.sslFacadeContext.isHandshakeCompleted()) { if (tioConfig.getAioListener() != null) { try { tioConfig.getAioListener().onAfterSent(this, packet, isSentSuccess); } catch (Exception e) { log.error(e.toString(), e); } } if (tioConfig.statOn) { tioConfig.groupStat.sentPackets.incrementAndGet(); stat.sentPackets.incrementAndGet(); } if (CollUtil.isNotEmpty(tioConfig.ipStats.durationList)) { try { for (Long v : tioConfig.ipStats.durationList) { IpStat ipStat = tioConfig.ipStats.get(v, this); ipStat.getSentPackets().incrementAndGet(); tioConfig.getIpStatListener().onAfterSent(this, packet, isSentSuccess, ipStat); } } catch (Exception e) { log.error(e.toString(), e); } } } } catch (Throwable e) { log.error(e.toString(), e); } if (packet.getPacketListener() != null) { try { packet.getPacketListener().onAfterSent(this, packet, isSentSuccess); } catch (Throwable e) { log.error(e.toString(), e); } } } /** * @param asynchronousSocketChannel the asynchronousSocketChannel to set */ public void setAsynchronousSocketChannel(AsynchronousSocketChannel asynchronousSocketChannel) { this.asynchronousSocketChannel = asynchronousSocketChannel; if (asynchronousSocketChannel != null) { try { Node clientNode = createClientNode(asynchronousSocketChannel); setClientNode(clientNode); } catch (IOException e) { log.error(e.getMessage()); assignAnUnknownClientNode(); } } else { log.error("assignAnUnknownClientNode:{}", asynchronousSocketChannel); assignAnUnknownClientNode(); } } /** * 等价于:setAttribute(DEFAULT_ATTUBITE_KEY, value)
* 仅仅是为了内部方便,不建议大家使用
* * @deprecated 不建议各位同学使用这个方法,建议使用set("name1", object1) * @param value * @author tanyaowu */ public void setAttribute(Object value) { set(value); } /** * 等价于:set(DEFAULT_ATTUBITE_KEY, value)
* 等价于:setAttribute(Object value)
* * @deprecated 不建议各位同学使用这个方法,建议使用set("name1", object1) * @param value */ public void set(Object value) { set(DEFAULT_ATTUBITE_KEY, value); } /** * @param remoteNode the remoteNode to set */ public void setClientNode(Node clientNode) { if (!this.tioConfig.isShortConnection) { if (this.clientNode != null) { tioConfig.clientNodes.remove(this); } } this.clientNode = clientNode; if (this.tioConfig.isShortConnection) { return; } if (this.clientNode != null && !Objects.equals(UNKNOWN_ADDRESS_IP, this.clientNode.getIp())) { tioConfig.clientNodes.put(this); // clientNodeTraceFilename = StrUtil.replaceAll(clientNode.toString(), ":", // "_"); } } /** * @param isClosed the isClosed to set */ public void setClosed(boolean isClosed) { this.isClosed = isClosed; if (isClosed) { if (clientNode == null || !UNKNOWN_ADDRESS_IP.equals(clientNode.getIp())) { // String before = this.toString(); assignAnUnknownClientNode(); // log.info("关闭前{}, 关闭后{}", before, this); } } } /** * @param tioConfig the tioConfig to set */ public void setTioConfig(TioConfig tioConfig) { this.tioConfig = tioConfig; if (tioConfig != null) { decodeRunnable = new DecodeRunnable(this, Threads.getTioExecutor()); handlerRunnable = new HandlerRunnable(this, Threads.getTioExecutor()); sendRunnable = new SendRunnable(this, Threads.getTioExecutor()); tioConfig.connections.add(this); } } public void setPacketNeededLength(Integer packetNeededLength) { this.packetNeededLength = packetNeededLength; } public void setReconnect(boolean isReconnect) { this.isReconnect = isReconnect; } /** * @param isRemoved the isRemoved to set */ public void setRemoved(boolean isRemoved) { this.isRemoved = isRemoved; } /** * @param serverNode the serverNode to set */ public void setServerNode(Node serverNode) { this.serverNode = serverNode; } public void setSslFacadeContext(SslFacadeContext sslFacadeContext) { this.sslFacadeContext = sslFacadeContext; } public void setToken(String token) { this.token = token; } // /** // * @param isTraceClient the isTraceClient to set // */ // public void setTraceClient(boolean isTraceClient) { // this.isTraceClient = isTraceClient; // } // /** // * @param isTraceSynPacket the isTraceSynPacket to set // */ // public void setTraceSynPacket(boolean isTraceSynPacket) { // this.isTraceSynPacket = isTraceSynPacket; // } /** * @param userid the userid to set 给框架内部用的,用户请勿调用此方法 */ public void setUserid(String userid) { this.userid = userid; } @Override public String toString() { StringBuilder sb = new StringBuilder(64); if (serverNode != null) { sb.append("server:").append(serverNode.toString()); } else { sb.append("server:").append("NULL"); } if (clientNode != null) { sb.append(", client:").append(clientNode.toString()); } else { sb.append(", client:").append("NULL"); } if (isVirtual) { sb.append(", virtual"); } return sb.toString(); } /** * @return the bsId */ public String getBsId() { return bsId; } /** * @param bsId the bsId to set */ public void setBsId(String bsId) { this.bsId = bsId; } public TioConfig getTioConfig() { return tioConfig; } /** * 是否是服务器端 * * @return * @author tanyaowu */ public abstract boolean isServer(); /** * @return the heartbeatTimeout */ public Long getHeartbeatTimeout() { return heartbeatTimeout; } /** * @param heartbeatTimeout the heartbeatTimeout to set */ public void setHeartbeatTimeout(Long heartbeatTimeout) { this.heartbeatTimeout = heartbeatTimeout; } public Integer getReadBufferSize() { if (readBufferSize != null && readBufferSize > 0) { return readBufferSize; } return this.tioConfig.getReadBufferSize(); } public void setReadBufferSize(Integer readBufferSize) { this.readBufferSize = Math.min(readBufferSize, TcpConst.MAX_DATA_LENGTH); } /** * @return the proxyClientNode */ public Node getProxyClientNode() { return proxyClientNode; } private void swithIpStat(IpStat oldIpStat, IpStat newIpStat, ChannelStat myStat) { oldIpStat.getHandledBytes().addAndGet(-myStat.getHandledBytes().get()); oldIpStat.getHandledPacketCosts().addAndGet(-myStat.getHandledPacketCosts().get()); oldIpStat.getHandledPackets().addAndGet(-myStat.getHandledPackets().get()); oldIpStat.getReceivedBytes().addAndGet(-myStat.getReceivedBytes().get()); oldIpStat.getReceivedPackets().addAndGet(-myStat.getReceivedPackets().get()); oldIpStat.getReceivedTcps().addAndGet(-myStat.getReceivedTcps().get()); oldIpStat.getRequestCount().addAndGet(-1); oldIpStat.getSentBytes().addAndGet(-myStat.getSentBytes().get()); oldIpStat.getSentPackets().addAndGet(-myStat.getSentPackets().get()); oldIpStat.getStart(); newIpStat.getHandledBytes().addAndGet(myStat.getHandledBytes().get()); newIpStat.getHandledPacketCosts().addAndGet(myStat.getHandledPacketCosts().get()); newIpStat.getHandledPackets().addAndGet(myStat.getHandledPackets().get()); newIpStat.getReceivedBytes().addAndGet(myStat.getReceivedBytes().get()); newIpStat.getReceivedPackets().addAndGet(myStat.getReceivedPackets().get()); newIpStat.getReceivedTcps().addAndGet(myStat.getReceivedTcps().get()); newIpStat.getRequestCount().addAndGet(1); newIpStat.getSentBytes().addAndGet(myStat.getSentBytes().get()); newIpStat.getSentPackets().addAndGet(myStat.getSentPackets().get()); newIpStat.getStart(); } /** * @param proxyClientNode the proxyClientNode to set */ public void setProxyClientNode(Node proxyClientNode) { this.proxyClientNode = proxyClientNode; if (proxyClientNode != null) { // 将性能数据进行转移 if (!Objects.equals(proxyClientNode.getIp(), clientNode.getIp())) { if (CollUtil.isNotEmpty(tioConfig.ipStats.durationList)) { try { for (Long v : tioConfig.ipStats.durationList) { IpStat oldIpStat = (IpStat) tioConfig.ipStats._get(v, this, true, false); IpStat newIpStat = (IpStat) tioConfig.ipStats.get(v, this); ChannelStat myStat = this.stat; swithIpStat(oldIpStat, newIpStat, myStat); } } catch (Exception e) { log.error(e.toString(), e); } } } } } public CloseCode getCloseCode() { return closeCode; } public void setCloseCode(CloseCode closeCode) { this.closeCode = closeCode; } /** * @author tanyaowu */ public static class CloseMeta { public Throwable throwable; public String remark; public boolean isNeedRemove; public Throwable getThrowable() { return throwable; } public void setThrowable(Throwable throwable) { this.throwable = throwable; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } public boolean isNeedRemove() { return isNeedRemove; } public void setNeedRemove(boolean isNeedRemove) { this.isNeedRemove = isNeedRemove; } } /** * 连接关闭码 * * @author tanyaowu */ public static enum CloseCode { /** * 没有提供原因码 */ NO_CODE((byte) 1), /** * 读异常 */ READ_ERROR((byte) 2), /** * 写异常 */ WRITER_ERROR((byte) 3), /** * 解码异常 */ DECODE_ERROR((byte) 4), /** * 通道未打开 */ CHANNEL_NOT_OPEN((byte) 5), /** * 读到的数据长度是0 */ READ_COUNT_IS_ZERO((byte) 6), /** * 对方关闭了连接 */ CLOSED_BY_PEER((byte) 7), /** * 读到的数据长度小于-1 */ READ_COUNT_IS_NEGATIVE((byte) 8), /** * 写数据长度小于0 */ WRITE_COUNT_IS_NEGATIVE((byte) 9), /** * 心跳超时 */ HEARTBEAT_TIMEOUT((byte) 10), /** * 连接失败 */ CLIENT_CONNECTION_FAIL((byte) 80), /** * SSL握手时发生异常 */ SSL_ERROR_ON_HANDSHAKE((byte) 50), /** * SSL session关闭了 */ SSL_SESSION_CLOSED((byte) 51), /** * SSL加密时发生异常 */ SSL_ENCRYPTION_ERROR((byte) 52), /** * SSL解密时发生异常 */ SSL_DECRYPT_ERROR((byte) 53), /** * 供用户使用 */ USER_CODE_0((byte) 100), /** * 供用户使用 */ USER_CODE_1((byte) 101), /** * 供用户使用 */ USER_CODE_2((byte) 102), /** * 供用户使用 */ USER_CODE_3((byte) 103), /** * 供用户使用 */ USER_CODE_4((byte) 104), /** * 供用户使用 */ USER_CODE_5((byte) 105), /** * 供用户使用 */ USER_CODE_6((byte) 106), /** * 供用户使用 */ USER_CODE_7((byte) 107), /** * 供用户使用 */ USER_CODE_8((byte) 108), /** * 供用户使用 */ USER_CODE_9((byte) 109), /** * 供用户使用 */ USER_CODE_10((byte) 110), /** * 初始值 */ INIT_STATUS((byte) 199), /** * 其它异常 */ OTHER_ERROR((byte) 200), /*** * 超出最大包长度 */ PACKET_TOO_LARGE((byte) 201); public static CloseCode from(Byte value) { CloseCode[] values = CloseCode.values(); for (CloseCode v : values) { if (Objects.equals(v.value, value)) { return v; } } return null; } Byte value; private CloseCode(Byte value) { this.value = value; } public Byte getValue() { return value; } public void setValue(Byte value) { this.value = value; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy