/** * 服务开始,初始化 * * @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); } }
/** * 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); } }