/* * Copyright (c) 2013, OpenCloudDB/MyCAT and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software;Designed and Developed mainly by many Chinese * opensource volunteers. you can redistribute it and/or modify it under the * terms of the GNU General Public License version 2 only, as published by the * Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Any questions about this component can be directed to it's project Web address * https://code.google.com/p/opencloudb/. * */ package com.talent.nio.communicate.receive; import io.netty.buffer.ByteBuf; import io.netty.buffer.CompositeByteBuf; import io.netty.buffer.Unpooled; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.lang.ArrayUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.talent.nio.api.Packet; import com.talent.nio.communicate.ChannelContext; import com.talent.nio.communicate.intf.DecoderIntf.DecodeException; import com.talent.nio.communicate.intf.DecoderIntf.PacketWithMeta; import com.talent.nio.debug.DebugUtils; import com.talent.nio.utils.SystemTimer; import com.talent.platform.threadpool.AbstractQueueRunnable; import com.talent.platform.threadpool.SynThreadPoolExecutor; import com.talent.platform.threadpool.intf.SynRunnableIntf; import com.talent.platform.threadpool.monitor.ThreadPoolMonitor; /** * 接收socket消息时,需要将消息组包。本类就是处理组包操作的。 * * @author 谭耀武 * @date 2012-08-09 * */ public class DecodeRunnable extends AbstractQueueRunnable<ByteBuf> { private static final Logger log = LoggerFactory.getLogger(DecodeRunnable.class); private ChannelContext channelContext = null; /** * 当前的字节数据 */ private ByteBuf lastDatas = null; /** * 计数器,用来统计总共有多少条消息被处理掉了 */ private static AtomicLong allProcessedMsgCount = new AtomicLong(); /** * // */ // private static BlockingQueue<Runnable> runnableQueue = null; private static SynThreadPoolExecutor<SynRunnableIntf> threadExecutor = null; /** * 初始化业务处理线程池 */ public static void init(SynThreadPoolExecutor<SynRunnableIntf> synThreadPoolExecutor) { threadExecutor = synThreadPoolExecutor; ThreadPoolMonitor.getInstance().register(threadExecutor); } /** * */ public DecodeRunnable(ChannelContext channelContext) { this.channelContext = channelContext; setRunnableName(DecodeRunnable.class.getSimpleName() + "[" + channelContext.getId() + "]"); } /** * 添加要组包的消息 * * @param datas */ public void addMsg(ByteBuf datas) { if (DebugUtils.isNeedDebug(channelContext)) { log.error("com.talent.nio.communicate.receive.DecodeRunnable.addMsg(byte[]):" + ArrayUtils.toString(datas)); try { log.error("com.talent.nio.communicate.receive.DecodeRunnable.addMsg(byte[]):" + new String(datas.array(), "utf-8")); } catch (UnsupportedEncodingException e) { log.error(e.getMessage(), e); } } getMsgQueue().add(datas); } /** * 清空处理的队列消息 */ public void clearMsgQueue() { getMsgQueue().clear(); lastDatas = null; } private int needLength = -1; @Override public void run() { while (getMsgQueue().size() > 0) { ByteBuf queuedatas = null; CompositeByteBuf datas = Unpooled.compositeBuffer(); if (lastDatas != null) { channelContext.getStatVo().setCurrentOgnzTimestamp(SystemTimer.currentTimeMillis()); lastDatas.readerIndex(0); datas.addComponents(lastDatas); lastDatas = null; } int count = 0; label_2: while ((queuedatas = getMsgQueue().poll()) != null) { queuedatas = queuedatas.order(channelContext.getByteOrder()); if (DebugUtils.isNeedDebug(channelContext)) { // long xx = 999999999999999999L; log.error("queuedatas:" + ArrayUtils.toString(queuedatas)); } datas.addComponents(queuedatas); channelContext.getStatVo().setCurrentOgnzTimestamp(SystemTimer.currentTimeMillis()); count++; if (needLength != -1) // 已经解析出消息所需要的总长度 { if (datas.capacity() < needLength) // 收到的数据还不够长 { // log.error("数据还不够长----capacity:{}, needLength:{}", datas.capacity(), needLength); continue; } else { // log.error("数据够了----capacity:{}, needLength:{}", datas.capacity(), needLength); break label_2; } } else // 还没有解析出消息所需要的总长度 { if (count == 50) { log.warn("等待组包的消息挺多的,马上提交{}个,提交后还有{}个等待组包", count, getMsgQueue().size()); break label_2; } } } channelContext.getStatVo().setCurrentOgnzTimestamp(SystemTimer.currentTimeMillis()); PacketWithMeta packetWithMeta = null; try { // ByteBuffer buffer = ByteBuffer.wrap(datas); datas.writerIndex(datas.capacity()); datas.readerIndex(0); packetWithMeta = channelContext.getDecoder().decode(datas, channelContext); needLength = -1; if (packetWithMeta == null) { // 数据不够,组不了包, lastDatas = datas; lastDatas.readerIndex(0); if (DebugUtils.isNeedDebug(channelContext)) { log.error("数据不够,组不了包:{}", lastDatas); } } else if (packetWithMeta.getPackets() == null || packetWithMeta.getPackets().size() == 0) { // 数据不够,组不了包, lastDatas = datas; lastDatas.readerIndex(0); needLength = packetWithMeta.getNeedLength(); if (DebugUtils.isNeedDebug(channelContext)) { log.error("数据不够,组不了包,需要的长度为:{}", needLength); } } else { int len = packetWithMeta.getPacketLenght(); // lastDatas = new byte[datas.capacity() - len]; // System.arraycopy(datas, len, lastDatas, 0, // lastDatas.length); if (datas.capacity() - len > 0) { lastDatas = datas.copy(len, datas.capacity() - len); if (DebugUtils.isNeedDebug(channelContext)) { log.error("组包后,还剩一点数据:{}, {}", datas.capacity() - len, lastDatas); } } else { lastDatas = null; if (DebugUtils.isNeedDebug(channelContext)) { log.error("组包后,数据刚好用完:{}", lastDatas); } } processMsgAndStat(packetWithMeta.getPackets(), len, false); } } catch (DecodeException e) { log.error(e.getMessage(), e); channelContext.getErrorPackageHandler().handle(channelContext.getSocketChannel(), channelContext, e.getMessage()); } } } /** * 处理消息并且统计消息数量 * * @param packet * @param msgLenght * @param isInvalid * false:正常 */ private void processMsgAndStat(List<Packet> packet, int msgLenght, boolean isInvalid) { try { if (DebugUtils.isNeedDebug(channelContext)) { log.error("com.talent.nio.communicate.receive.DecodeRunnable.processMsgAndStat(List<Packet>, int, boolean) 来了!"); } if (isInvalid) { return; } int num = processMsg(packet); getAllProcessedMsgCount().addAndGet(num); getProcessedMsgCount().addAndGet(num); getProcessedMsgByteCount().addAndGet(msgLenght); if (log.isDebugEnabled()) { long allReadCount = ChannelReader.getReadCount().get(); long myReadCount = channelContext.getStatVo().getReadCount().get(); log.debug("all processed [" + allProcessedMsgCount.get() + "];" + channelContext.getId() + " processed [" + this.getProcessedMsgCount().get() + "],waiting for process [" + this.getMsgQueue().size() + "];allReadCount[" + allReadCount + "];[" + channelContext.getId() + "] readCount[" + myReadCount + "]"); } } catch (Exception e) { log.error("", e); } } /** * 处理消息 * * @param msgHead * @param bodyData * @return 处理的消息条数 */ private int processMsg(List<Packet> packets) { try { if (DebugUtils.isNeedDebug(channelContext)) { log.error("packets:{}", packets); } submitTask(packets); return packets.size(); } catch (Exception e) { log.error("", e); } return 0; } /** * 提交任务到调度池 * * @param packets */ private void submitTask(List<Packet> packets) { HandlerRunnable packetHandlerRunnable = channelContext.getHandlerRunnable();// PacketHandlerRunnableFactory.getPacketHandlerRunnable(packet, if (DebugUtils.isNeedDebug(channelContext)) { log.error("packets:{}", packets); } packetHandlerRunnable.addMsg(packets); threadExecutor.execute(packetHandlerRunnable); } /** * @param args */ public static void main(String[] args) { byte[] bs1 = new byte[] { 1, 10, 11, 12 }; byte[] bs2 = new byte[] { 2, 2, 2, 2 }; byte[] bs3 = new byte[] { 3, 3, 3, 3 }; byte[] bs4 = new byte[] { 4, 4, 4, 4 }; byte[] bs5 = new byte[] { 5, 5, 5, 5 }; byte[] bs6 = new byte[] { 6, 6, 6, 6 }; ByteBuffer buffer1 = ByteBuffer.allocate(1024); buffer1.put(bs1); buffer1.flip(); ByteBuf buf1 = Unpooled.copiedBuffer(buffer1);// .copiedBuffer(bs1); buffer1.put(bs3); ByteBuf buf2 = Unpooled.copiedBuffer(bs2); ByteBuf buf3 = Unpooled.copiedBuffer(bs3); ByteBuf buf4 = Unpooled.copiedBuffer(bs4); ByteBuf buf5 = Unpooled.copiedBuffer(bs5); ByteBuf buf6 = Unpooled.copiedBuffer(bs6); CompositeByteBuf cb = Unpooled.compositeBuffer(); cb.addComponents(buf1, buf2, buf3); byte dd = cb.getByte(0); CompositeByteBuf cb2 = Unpooled.compositeBuffer(); cb.addComponents(buf4, buf5, buf6); // cb.c // cb2.writerIndex(128 * 1024); cb.addComponent(cb2); Long number = cb2.readLong(); // causes IllegalBufferAccessException // here! } @Override public String getCurrentProcessor() { return this.getClass().getName(); } public static AtomicLong getAllProcessedMsgCount() { return allProcessedMsgCount; } public static SynThreadPoolExecutor<SynRunnableIntf> getThreadExecutor() { return threadExecutor; } public ChannelContext getSocketChannelContext() { return channelContext; } public void setSocketChannelContext(ChannelContext channelContext) { this.channelContext = channelContext; } }