/**
  * 服务开始,初始化
  *
  * @throws Exception
  */
 public void start() throws Exception {
   if (antenna != null) {
     throw new Exception("antenna is not null, may have run before");
   }
   antenna = DatagramChannel.open();
   antenna.socket().bind(new InetSocketAddress(port));
   System.out.println("udp connector port:" + port);
   // non-blocking
   antenna.configureBlocking(false);
   antenna
       .socket()
       .setReceiveBufferSize(
           1024 * 1024 * PropertyUtil.getPropertyInt("CLIENT_UDP_BUFFER_RECEIVE"));
   antenna
       .socket()
       .setSendBufferSize(1024 * 1024 * PropertyUtil.getPropertyInt("CLIENT_UDP_BUFFER_SEND"));
   System.out.println("udp connector recv buffer size:" + antenna.socket().getReceiveBufferSize());
   System.out.println("udp connector send buffer size:" + antenna.socket().getSendBufferSize());
   // 初始化接收和发送服务
   this.receiver = new Receiver(antenna);
   this.receiver.init();
   this.sender = new Sender(antenna);
   this.sender.init();
   // 启动接收和发送线程
   this.senderThread = new Thread(sender, "AsynUdpConnector-sender");
   this.receiverThread = new Thread(receiver, "AsynUdpConnector-receiver");
   this.receiverThread.start();
   this.senderThread.start();
 }
 /**
  * 系统参数配置
  *
  * @throws Exception
  */
 public void initSystem() throws Exception {
   PropertyConfigurator.configure("Log4j.properties");
   InternalLoggerFactory.setDefaultFactory(new Slf4JLoggerFactory());
   log.info(System.getProperty("file.encoding"));
   System.setProperty(
       "io.netty.recycler.maxCapacity.default",
       PropertyUtil.getProperty("io.netty.recycler.maxCapacity.default"));
   System.setProperty("io.netty.leakDetectionLevel", "paranoid");
   DbHelper.init();
 }
 private void autoClean() {
   float percent = PropertyUtil.getPropertyFloat("CLEANER_AUTO_RUN_MEM_PERCENT");
   if (percent >= 1 || percent <= 0) {
     return;
   }
   Runtime rt = Runtime.getRuntime();
   if ((rt.totalMemory() - rt.freeMemory()) / (double) rt.maxMemory() > percent) {
     System.out.println("run auto clean...");
     cleaner.wakeup();
   }
 }
 public void initTcpConnector() throws Exception {
   if (!"YES".equalsIgnoreCase(PropertyUtil.getProperty("TCP_CONNECTOR_ENABLE"))) {
     return;
   }
   tcpConnector = new NIOTcpConnector();
   tcpConnThread = new Thread(tcpConnector, "IMServer-NIOTcpConnector");
   synchronized (tcpConnector) {
     tcpConnThread.start();
     tcpConnector.wait();
   }
 }
public class IMServer {
  private static final Logger log = LoggerFactory.getLogger(IMServer.class);

  public static IMServer server;

  private boolean stoped = false;

  int workerNum = PropertyUtil.getPropertyInt("CLIENT_UDP_WORKER_THREAD"); // fixed work threads

  private UdpConnector udpConnector;

  private Thread tcpConnThread;
  private NIOTcpConnector tcpConnector;

  private NodeStatus nodeStatus = NodeStatus.getInstance();
  /** 推送消息监听器列表 */
  private ArrayList<PushMessageListener> pushMessageListeners = new ArrayList<>();

  private ArrayList<UDPMessenger> workerList = new ArrayList<UDPMessenger>();

  /** Service集合 */
  Service[] services = new Service[] {new BroadCastService()};

  private Thread clearnThread = null;
  private ClientStatMachineCleaner cleaner = null;

  private Thread cmdThread = null;
  private IMServerConsole console = null;

  private Thread pushThread = null;
  private NettyPushListener pushListener = null;

  private long startTime;

  private IMServer() {}

  public static IMServer getInstance() {
    if (server == null) {
      synchronized (IMServer.class) {
        if (server == null) {
          server = new IMServer();
        }
      }
    }
    return server;
  }

  public void init() throws Exception {
    initSystem();
    initPushListener();
    initConsole();
    initUdpConnector();
    initTcpConnector();
    initWorkers();
    initServices();
    initCleaner();
  }
  /**
   * 系统参数配置
   *
   * @throws Exception
   */
  public void initSystem() throws Exception {
    PropertyConfigurator.configure("Log4j.properties");
    InternalLoggerFactory.setDefaultFactory(new Slf4JLoggerFactory());
    log.info(System.getProperty("file.encoding"));
    System.setProperty(
        "io.netty.recycler.maxCapacity.default",
        PropertyUtil.getProperty("io.netty.recycler.maxCapacity.default"));
    System.setProperty("io.netty.leakDetectionLevel", "paranoid");
    DbHelper.init();
  }

  public void initConsole() throws Exception {
    console = new IMServerConsole();
    cmdThread = new Thread(console, "IMServer-console");
    cmdThread.setDaemon(true);
    cmdThread.start();
  }

  public void initUdpConnector() throws Exception {
    System.out.println("start connector...");
    udpConnector = new UdpConnector();
    udpConnector.start();
  }

  public void initTcpConnector() throws Exception {
    if (!"YES".equalsIgnoreCase(PropertyUtil.getProperty("TCP_CONNECTOR_ENABLE"))) {
      return;
    }
    tcpConnector = new NIOTcpConnector();
    tcpConnThread = new Thread(tcpConnector, "IMServer-NIOTcpConnector");
    synchronized (tcpConnector) {
      tcpConnThread.start();
      tcpConnector.wait();
    }
  }

  public void initWorkers() {
    System.out.println("start " + workerNum + " workers...");
    for (int i = 0; i < workerNum; i++) {
      UDPMessenger worker = new UDPMessenger(udpConnector, nodeStatus);
      workerList.add(worker);
      Thread t = new Thread(worker, "IMServer-worker-" + i);
      worker.setHostThread(t);
      t.setDaemon(true);
      t.start();
    }
  }
  /**
   * <b>concurrent-safe</b> 加入消息监听器
   *
   * @param listener
   */
  public void addPushMessageListener(final PushMessageListener listener) {
    synchronized (listener) {
      if (!pushMessageListeners.contains(listener)) {
        pushMessageListeners.add(listener);
      }
    }
  }

  void firePushMessageReceived(final PushMessage message) {
    for (PushMessageListener listener : pushMessageListeners) {
      listener.received(message);
    }
  }
  /**
   * <b>concurrent-safe</b> 删除消息监听器
   *
   * @param listner
   */
  public void removePushMessageListener(final PushMessageListener listner) {
    synchronized (listner) {
      pushMessageListeners.remove(listner);
    }
  }

  public void initServices() {
    for (Service service : services) {
      service.install();
    }
  }

  public void stopServices() {
    for (Service service : services) {
      service.uninstall();
    }
  }

  public void initCleaner() throws Exception {
    cleaner = new ClientStatMachineCleaner();
    clearnThread = new Thread(cleaner, "IMServer-cleaner");
    clearnThread.start();
  }

  public void initPushListener() throws Exception {
    pushListener = new NettyPushListener();
    pushThread = new Thread(pushListener, "IMServer-push-listener");
    pushThread.start();
  }

  public void start() throws Exception {
    System.out.println("working dir: " + System.getProperty("user.dir"));
    init();

    final Thread mainT = Thread.currentThread();

    Runtime.getRuntime()
        .addShutdownHook(
            new Thread() {
              public void run() {
                stoped = true;
                System.out.println("shut down server... ");
                try {
                  mainT.join();
                  System.out.println("server is down, bye ");
                } catch (Exception e) {
                  System.out.println("服务器关闭错误");
                }
              }
            });
    this.startTime = System.currentTimeMillis();
    System.out.println("server is up ");
    while (stoped == false) {
      try {
        synchronized (this) {
          this.wait(1000 * 60);
          if (stoped == false) {
            autoClean();
          }
        }
      } catch (Exception e) {
      }
    }
    this.quit();
  }

  private void autoClean() {
    float percent = PropertyUtil.getPropertyFloat("CLEANER_AUTO_RUN_MEM_PERCENT");
    if (percent >= 1 || percent <= 0) {
      return;
    }
    Runtime rt = Runtime.getRuntime();
    if ((rt.totalMemory() - rt.freeMemory()) / (double) rt.maxMemory() > percent) {
      System.out.println("run auto clean...");
      cleaner.wakeup();
    }
  }

  public void stop() {
    this.stoped = true;
    synchronized (this) {
      this.notifyAll();
    }
  }

  protected void quit() throws Exception {
    try {
      stopServices();
      stopWorkers();
      stopUdpConnector();
      stopTcpConnector();
      stopCleaner();
      stopPushListener();
    } catch (Throwable t) {
      t.printStackTrace();
    }
    saveStatus();
  }

  public void stopWorkers() throws Exception {
    for (int i = 0; i < workerList.size(); i++) {
      try {
        workerList.get(i).stop();
      } catch (Exception e) {
        System.out.println("启动worker错误");
      }
    }
  }

  public void stopUdpConnector() throws Exception {
    if (udpConnector == null) {
      return;
    }
    udpConnector.stop();
  }

  public void stopTcpConnector() throws Exception {
    if (tcpConnector == null || tcpConnThread == null) {
      return;
    }
    tcpConnector.stop();
    tcpConnThread.join();
  }

  public void stopCleaner() throws Exception {
    cleaner.stop();
    try {
      clearnThread.interrupt();
    } catch (Exception e) {
      System.out.println("缓存清除器执行错误");
    }
  }

  public void stopPushListener() throws Exception {
    pushListener.stop();
    pushThread.join();
  }

  public void saveStatus() throws Exception {
    nodeStatus.saveToFile();
  }

  public String getStatusString() {
    StringBuffer sb = new StringBuffer();

    String end = "\r\n";

    sb.append("server start up at: ")
        .append(DateTimeUtil.formatDate(new Date(this.startTime)))
        .append(end);
    long runtime = System.currentTimeMillis() - this.startTime;
    sb.append("up time: ")
        .append(runtime / (1000 * 3600 * 24))
        .append(" day ")
        .append(runtime / (1000 * 3600))
        .append(" hour ")
        .append(runtime / (1000 * 60))
        .append(" minute")
        .append(end);
    sb.append("messagers: ").append(this.workerList.size()).append(end);
    sb.append("current stat machines: ").append(nodeStatus.size()).append(end);
    sb.append("udp recieve packages: ").append(this.udpConnector.getInqueueIn()).append(end);
    sb.append("udp recieve packages pending: ")
        .append(this.udpConnector.getInqueueIn() - this.udpConnector.getInqueueOut())
        .append(end);
    sb.append("udp send packages: ").append(this.udpConnector.getOutqueueIn()).append(end);
    sb.append("udp send packages pending: ")
        .append(this.udpConnector.getOutqueueIn() - this.udpConnector.getOutqueueOut())
        .append(end);
    sb.append("jvm  max  mem: ").append(Runtime.getRuntime().maxMemory()).append(end);
    sb.append("jvm total mem: ").append(Runtime.getRuntime().totalMemory()).append(end);
    sb.append("jvm  free mem: ").append(Runtime.getRuntime().freeMemory()).append(end);
    sb.append("last clean time: ")
        .append(DateTimeUtil.formatDate(new Date(this.cleaner.getLastCleanTime())))
        .append(end);
    sb.append("messengers threads:----------------------").append(end);
    for (int i = 0; i < workerList.size(); i++) {
      Thread t = workerList.get(i).getHostThread();
      sb.append(t.getName() + " stat: " + t.getState().toString()).append(end);
    }
    return sb.toString();
  }

  public String getUuidStatString(String uuid) {
    ClientStatMachine csm = this.nodeStatus.getClientStat(uuid);
    if (csm == null) {
      return null;
    }
    StringBuffer sb = new StringBuffer();
    String end = "\r\n";

    sb.append("stat of   uuid: " + uuid).append(end);
    sb.append("last tick time: " + DateTimeUtil.formatDate(new Date(csm.getLastTick())))
        .append(end);
    sb.append("last ip addres: " + csm.getLastAddr()).append(end);
    sb.append(
            "last tcp  time: "
                + DateTimeUtil.formatDate(
                    new Date(
                        csm.getMessengerTask() == null
                            ? 0
                            : csm.getMessengerTask().getLastActive())))
        .append(end);
    sb.append("0x10   message: " + csm.has0x10Message()).append(end);
    sb.append("last 0x10 time: " + DateTimeUtil.formatDate(new Date(csm.getLast0x10Time())))
        .append(end);
    sb.append("0x11   message: " + csm.get0x11Message()).append(end);
    sb.append("last 0x11 time: " + DateTimeUtil.formatDate(new Date(csm.getLast0x11Time())))
        .append(end);
    sb.append("0x20   message: " + csm.has0x20Message()).append(end);
    sb.append("last 0x20 time: " + DateTimeUtil.formatDate(new Date(csm.getLast0x20Time())))
        .append(end);
    sb.append("0x20 arry  len: " + csm.getMessage0x20Len()).append(end);

    return sb.toString();
  }

  public void cleanExpiredMachines(int hours) {
    cleaner.setExpiredHours(hours);
    cleaner.wakeup();
  }

  public void pushInstanceMessage(ServerMessage sm) throws Exception {
    if (sm == null || sm.getData() == null || sm.getSocketAddress() == null) {
      return;
    }
    if (udpConnector != null) {
      udpConnector.send(sm);
    }
  }

  public static void main(String[] args) {
    IMServer server = IMServer.getInstance();
    try {
      server.start();

    } catch (Exception e) {
      e.printStackTrace();
      System.exit(1);
    } catch (Throwable t) {
      t.printStackTrace();
      System.exit(1);
    }
  }
}
/** UDP服务端 */
public class UdpConnector {

  /** UDP通道 */
  protected DatagramChannel antenna; // 天线
  /** 接收器 */
  protected Receiver receiver;
  /** 发送器 */
  protected Sender sender;
  /** 接收线程 */
  protected Thread receiverThread;
  /** 发送线程 */
  protected Thread senderThread;

  // boolean started = false;
  // boolean stoped = false;

  /** 从配置文件读取端口号 */
  protected int port = PropertyUtil.getPropertyInt("CLIENT_UDP_PORT");

  /**
   * 设定号
   *
   * @param port
   */
  public void setPort(int port) {
    this.port = port;
  }

  /**
   * 取得端口号
   *
   * @return
   */
  public int getPort() {
    return this.port;
  }

  public void init() {}

  /**
   * 服务开始,初始化
   *
   * @throws Exception
   */
  public void start() throws Exception {
    if (antenna != null) {
      throw new Exception("antenna is not null, may have run before");
    }
    antenna = DatagramChannel.open();
    antenna.socket().bind(new InetSocketAddress(port));
    System.out.println("udp connector port:" + port);
    // non-blocking
    antenna.configureBlocking(false);
    antenna
        .socket()
        .setReceiveBufferSize(
            1024 * 1024 * PropertyUtil.getPropertyInt("CLIENT_UDP_BUFFER_RECEIVE"));
    antenna
        .socket()
        .setSendBufferSize(1024 * 1024 * PropertyUtil.getPropertyInt("CLIENT_UDP_BUFFER_SEND"));
    System.out.println("udp connector recv buffer size:" + antenna.socket().getReceiveBufferSize());
    System.out.println("udp connector send buffer size:" + antenna.socket().getSendBufferSize());
    // 初始化接收和发送服务
    this.receiver = new Receiver(antenna);
    this.receiver.init();
    this.sender = new Sender(antenna);
    this.sender.init();
    // 启动接收和发送线程
    this.senderThread = new Thread(sender, "AsynUdpConnector-sender");
    this.receiverThread = new Thread(receiver, "AsynUdpConnector-receiver");
    this.receiverThread.start();
    this.senderThread.start();
  }

  /**
   * 停止服务
   *
   * @throws Exception
   */
  public void stop() throws Exception {
    receiver.stop();
    sender.stop();
    try {
      receiverThread.join();
    } catch (Exception e) {
      e.printStackTrace();
    }
    try {
      senderThread.join();
    } catch (Exception e) {
      e.printStackTrace();
    }
    try {
      antenna.socket().close();
    } catch (Exception e) {
    }
    try {
      antenna.close();
    } catch (Exception e) {
    }
  }

  /**
   * 取得接收者接待事件数
   *
   * @return
   */
  public long getInqueueIn() {
    return this.receiver.queueIn.longValue();
  }

  /**
   * 取得接收者处理事件数
   *
   * @return
   */
  public long getInqueueOut() {
    return this.receiver.queueOut.longValue();
  }

  /**
   * 取得发送者接待事件数
   *
   * @return
   */
  public long getOutqueueIn() {
    return this.sender.queueIn.longValue();
  }

  /**
   * 取得发送者处理事件数
   *
   * @return
   */
  public long getOutqueueOut() {
    return this.sender.queueOut.longValue();
  }

  /**
   * 取得未处理消息
   *
   * @return
   * @throws Exception
   */
  public ClientMessage receive() throws Exception {
    return receiver.receive();
  }

  /**
   * 发送服务端消息
   *
   * @param message
   * @return
   * @throws Exception
   */
  public boolean send(ServerMessage message) throws Exception {
    return sender.send(message);
  }
}
Exemple #7
0
/**
 * UDP模式向终端发送消息
 *
 * @author [email protected]
 * @version [DDPush, 2015-3-8]
 */
public class Sender implements Runnable {
  protected DatagramChannel channel;
  protected AtomicLong queueIn = new AtomicLong(0);
  protected AtomicLong queueOut = new AtomicLong(0);

  protected int bufferSize =
      Constant.PUSH_MSG_HEADER_LEN + PropertyUtil.getPropertyInt("PUSH_MSG_MAX_CONTENT_LEN");

  protected boolean stoped = false;
  protected ByteBuffer buffer;

  protected Object enQueSignal = new Object();

  protected ConcurrentLinkedQueue<ServerMessage> mq = new ConcurrentLinkedQueue<ServerMessage>();

  public Sender(DatagramChannel channel) {
    this.channel = channel;
  }

  public void init() {
    buffer = ByteBuffer.allocate(bufferSize);
  }

  public void stop() {
    this.stoped = true;
  }

  public void run() {
    while (!this.stoped) {
      try {
        synchronized (enQueSignal) {
          while (mq.isEmpty() == true && stoped == false) {
            try {
              enQueSignal.wait(1);
            } catch (InterruptedException e) {

            }
            // System.out.println("sender wake up");
          }
          processMessage();
        }
      } catch (Exception e) {
        e.printStackTrace();
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }
  }

  protected void processMessage() throws Exception {
    buffer.clear();
    ServerMessage pendingMessage = dequeue();
    if (pendingMessage == null) {
      // Thread.yield();
      return;
    }
    buffer.put(pendingMessage.getData());
    buffer.flip();
    channel.send(buffer, pendingMessage.getSocketAddress());
    // System.out.println(DateTimeUtil.getCurDateTime()+"
    // s:"+StringUtil.convert(pendingMessage.getData())+" to
    // :"+pendingMessage.getSocketAddress().toString());
  }

  protected boolean enqueue(ServerMessage message) {
    boolean result = mq.add(message);
    if (result == true) {
      queueIn.addAndGet(1);
    }
    return result;
  }

  protected ServerMessage dequeue() {
    ServerMessage m = mq.poll();
    if (m != null) {
      queueOut.addAndGet(1);
    }
    return m;
  }

  public boolean send(ServerMessage message) {
    return enqueue(message);
  }
}