a problem in my app Performance Testing
Trustin Lee
trustin at gmail.com
Mon Jan 3 21:58:03 EST 2011
Your decoder implementation is incorrect. There's no need to call Channel.isReadable()and you need to check if there's enough data in the buffer before decoding. Please refer to te user guide and the examples like Factorial
--
Trustin Lee - http://gleamynode.net/
Sent from a mobile device - please excuse the brevity.
On Dec 27, 2010, at 11:13 AM, chris <zz12847643 at gmail.com> wrote:
>
> I'm sorry for my bad English writting.
> cut in short..
>
> i'm developping a webgame,when i was doing the performance testing upon
> Concurrency 4000
> , console print the exception as follows :
>
> java.lang.ArrayIndexOutOfBoundsException
> at java.lang.System.arraycopy(Native Method)
> at
> org.jboss.netty.buffer.HeapChannelBuffer.setBytes(HeapChannelBuffer.java:137)
> at
> org.jboss.netty.buffer.HeapChannelBuffer.setBytes(HeapChannelBuffer.java:130)
> at
> org.jboss.netty.buffer.AbstractChannelBuffer.writeBytes(AbstractChannelBuffer.java:462)
> at
> org.jboss.netty.buffer.DynamicChannelBuffer.ensureWritableBytes(DynamicChannelBuffer.java:85)
> at
> org.jboss.netty.buffer.DynamicChannelBuffer.writeBytes(DynamicChannelBuffer.java:239)
> at
> org.jboss.netty.buffer.AbstractChannelBuffer.writeBytes(AbstractChannelBuffer.java:457)
> at
> org.jboss.netty.buffer.AbstractChannelBuffer.writeBytes(AbstractChannelBuffer.java:450)
> at
> org.jboss.netty.handler.codec.frame.FrameDecoder.messageReceived(FrameDecoder.java:213)
> at
> org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:274)
> at
> org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:261)
> at
> org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:350)
> at
> org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:281)
> at
> org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:201)
> at
> org.jboss.netty.util.internal.IoWorkerRunnable.run(IoWorkerRunnable.java:46)
> at
> java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
> at
> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
> at java.lang.Thread.run(Thread.java:619)
>
>
>
> ackage net.sy599.mahjong.socket.server;
>
> import java.net.InetSocketAddress;
> import java.util.List;
> import java.util.Map;
> import java.util.concurrent.ExecutorService;
> import java.util.concurrent.Executors;
>
> import net.sy599.mahjong.common.context.MahjongContext;
> import net.sy599.mahjong.polling.TableAssignmentExecutor;
>
> import org.apache.log4j.xml.DOMConfigurator;
> import org.jboss.netty.bootstrap.ServerBootstrap;
> import org.jboss.netty.channel.ChannelFactory;
> import org.jboss.netty.channel.ChannelPipelineFactory;
> import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
> import org.slf4j.Logger;
> import org.slf4j.LoggerFactory;
> import org.springframework.context.ApplicationContext;
>
> /** bootstrap
> *
> * @author chris
> */
> public class GameServerBootStrap
> {
> /**
> * serversocket
> */
> private Map bootstrapConfigMap = null;
>
> private List roomIdList = null;
>
> private static final Logger LOGGER = LoggerFactory.getLogger("sys");
>
> /**
> * port
> */
> private Integer port = null;
>
> public static void main(String[] args)
> {
> DOMConfigurator.configure("../config/log4j.xml");
>
> LOGGER.info("spring Bean factory init ...");
>
> ApplicationContext context = MahjongContext.getContext();
>
> LOGGER.info(" spring Bean factory init complete !!");
>
> MahjongAgentServer server =
> context.getBean("agentServer",MahjongAgentServer.class);
>
> ChannelPipelineFactory pipeFactory =
> context.getBean("pipeFacotory",ChannelPipelineFactory.class);
>
> ChannelFactory factory = new
> NioServerSocketChannelFactory(Executors.newCachedThreadPool(),
> Executors.newCachedThreadPool());
>
> ServerBootstrap bootstrap = new ServerBootstrap(factory);
>
> bootstrap.setOptions(server.getBootstrapConfigMap());
>
> bootstrap.setPipelineFactory(pipeFactory);
>
> ExecutorService executorService = Executors.newCachedThreadPool();
>
> List idList = server.getRoomIdList();
>
> for(Integer i: idList)
> {
> executorService.execute(new TableAssignmentExecutor(i));
> }
>
> executorService.shutdown();
>
> LOGGER.info("Table Assignment Executor startup success..");
>
> bootstrap.bind(new InetSocketAddress(server.getPort()));
>
>
> }
>
>
>
> package net.sy599.mahjong.socket.handler;
>
> import java.nio.charset.Charset;
> import java.util.HashMap;
> import java.util.Map;
>
> import net.sy599.mahjong.common.secret.BufferEncrypt;
>
> import org.jboss.netty.buffer.ChannelBuffer;
> import org.jboss.netty.buffer.ChannelBuffers;
> import org.jboss.netty.channel.Channel;
> import org.jboss.netty.channel.ChannelHandlerContext;
> import org.jboss.netty.handler.codec.frame.FrameDecoder;
> import org.slf4j.Logger;
> import org.slf4j.LoggerFactory;
>
>
> /** decoder for game socket
> * @author chris
> *
> */
> public class ActionDecoder extends FrameDecoder
> {
>
> private static final Logger LOGGER = LoggerFactory.getLogger("sys");
>
> @Override
> protected Object decode(ChannelHandlerContext ctx, Channel channel,
> ChannelBuffer buffer) throws Exception
> {
> Map map = null;
> if (channel.isReadable())
> {
> byte[] tou = new byte[8];
> buffer.getBytes(0, tou);
> String str = new String(tou,Charset.forName("utf-8"));
> if (str.startsWith(" "
> +""
> +" "+"\0";
> byte[] xmlarray = xml.getBytes(Charset.forName("utf-8"));
> ChannelBuffer anquanHeader = ChannelBuffers.dynamicBuffer();
> anquanHeader.writeBytes(xmlarray);
> channel.write(anquanHeader);
> return map;
> }
> buffer.readByte(); //i
> buffer.readByte(); //c
> short cmdNum = buffer.readShort(); //cmd
> buffer.readByte(); //mainver
> buffer.readByte(); //subver
> short a = buffer.readShort(); //length
> buffer.readByte();
> byte[] content = new byte[a];
> buffer.readBytes(content);
> byte[] finalbuffer = new BufferEncrypt().CrevasseBuffer(content, 0, a, 1,
> BufferEncrypt.m_RecvByteMap);
> ChannelBuffer contentBuffer = ChannelBuffers.wrappedBuffer(finalbuffer);
> map = new HashMap();
> map.put(cmdNum, contentBuffer);
> }
> return map;
> }
> }
>
>
> /** game socket handler
> *
> * @author chris
> *
> */
> public class ActionHandler extends SimpleChannelHandler {
> /**
> *
> */
> private CommandSchedular command = null;
> private static final Logger LOGGER = LoggerFactory.getLogger("sys");
>
> @Override
> public void writeRequested(ChannelHandlerContext ctx, MessageEvent e)
> throws Exception {
> ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
> Channels.write(ctx, e.getFuture(), buffer);
> }
>
> @Override
> public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
> throws Exception {
> e.getCause().printStackTrace();
> //ctx.getChannel().close();
> }
>
> @Override
> public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
> throws Exception {
> Map map = (Map) e.getMessage();
> Short cmdNum = map.keySet().iterator().next();
> command.execute(cmdNum, map.get(cmdNum), e.getChannel());
> }
>
> public void setCommand(CommandSchedular command) {
> this.command = command;
> }
>
> @Override
> public void channelDisconnected(ChannelHandlerContext ctx,
> ChannelStateEvent e) throws Exception {
> e.getChannel().close();
> }
>
> @Override
> public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
> throws Exception {
> Channel channel = e.getChannel();
> int channelId = channel.getId();
> channel.disconnect();
> ChannelPersonMap channelPersonMap =
> MahjongContext.getContext().getBean(BeanKey.CHANNELPERSONVIEWER,
> ChannelPersonMap.class);
> Player player = channelPersonMap.getOnlinePlayers().get(channelId);
> MahjongTablePool tablePool =
> MahjongContext.getContext().getBean(BeanKey.MAHJONGTABLEPOOL,
> MahjongTablePool.class);
> if (null == player) {
>
> return;
> }
> channelPersonMap.getOnlinePlayers().remove(channelId);
> int tableId = player.getTableId();
> int roomId = player.getRoomId();
> MahjongTable table = tablePool.getTableByRoomIdAndTableId(roomId,
> tableId);
> if(table.getPersonGroup().isEmpty())
> {
> table.stopPlaying(true);
> }
>
> if (Player.PLAYING != player.getStatus())
> {
>
> table.setTimes(0);
>
> RoomPersonMap roomPersonViewer =
> MahjongContext.getContext().getBean(BeanKey.ROOMPERSONVIEWER,
> RoomPersonMap.class);
> WaitingQueue waitingQueue =
> MahjongContext.getContext().getBean(BeanKey.WAITINGQUEUE,
> WaitingQueue.class);
>
> waitingQueue.removePersonByRoomIdAndPlayer(player);
> tablePool.removePersonByRoomIdAndPlayer(player);
>
> table.getSeatMap().remove(player.getSeatId());
> roomPersonViewer.deletePersonByRoomIdAndPlayer(player);
> RoomEmptyTableMap tableMap =
> MahjongContext.getContext().getBean(BeanKey.ROOMEMPTYTABLEVIEWER,
> RoomEmptyTableMap.class);
> List list = tableMap.getEmptyTableListByRoomId(roomId);
> if (!list.contains(table)) {
> list.add(table);
> }
> ChannelBuffer bufferHeader = writeHeader(CmdKey.PLAYERLOGOUTRESPONSE);
> bufferHeader.writeDouble(player.getXiaoneiId());
> ChannelBuffer bufferTail = writeTail(bufferHeader, null);
> table.getPersonGroup().write(bufferTail);
> } else
> {
>
> synchronized (table.getTIMEOUTLOCK()) {
> if (player.getXiaoneiId().longValue() ==
> table.getNowDiscardPlayer().getXiaoneiId().longValue()&&table.getWaitingCount()==1)
> {
>
> table.getResponse1List().clear();
> table.getResponse3List().clear();
> table.getTask().cancel();
> table.getTimer().purge();
> MahjongContext.getContext().getBean(BeanKey.DISCARD,
> Discard.class).execute(RespBean.newDefaultDiscard(table, player));
>
> } else if(table.getWaitingCount()==3){
>
> player.setAuto(true);
> List list = table.getResponse3List();
> boolean flag = true;
> for (RespBean bean : list) {
> if (bean.getXiaoneiId() == player.getXiaoneiId().longValue()) {
> flag = false;
> }
> }
> if (flag) {
>
> table.addResponse(RespBean.defaultInstance(table, (byte) 1,
> player.getXiaoneiId()));
> }
> }
> }
> ChannelBuffer bufferHeader = writeHeader(CmdKey.PLAYERLOGOUTRESPONSE);
> bufferHeader.writeDouble(player.getXiaoneiId());
> ChannelBuffer bufferTail = writeTail(bufferHeader, null);
> table.getPersonGroup().write(bufferTail);
> }
> super.channelClosed(ctx, e);
> }
>
>
> }
>
> /** *
> * @author chris
> *
> */
> public class MahjongChannelPipelineFactory implements ChannelPipelineFactory
> {
> /**
> * handlers
> */
> private ChannelHandler[] handlers = null;
>
> @Override
> public ChannelPipeline getPipeline() throws Exception
> {
> ChannelPipeline p = Channels.pipeline();
> //p.addLast("lengthDecoder",
> MahjongContext.getContext().getBean(BeanKey.LENGTHDECODER,
> LengthFieldBasedFrameDecoder.class));
> p.addLast("actionDecoder",
> MahjongContext.getContext().getBean(BeanKey.ACTIONDECODER,
> ActionDecoder.class));
> p.addLast("actionHandler",
> MahjongContext.getContext().getBean(BeanKey.ACTIONHANDLER,
> ActionHandler.class));
> return p;
> }
>
>
> }
>
>
>
>
>
>
> public class MessageManager
> {
> private static final Logger LOGGER = LoggerFactory.getLogger("sys");
> /**
> * 统一成功编码
> */
> private static final int DEFAULT_SUCCESS_MESSAGE = 0;
>
> /**
> * head的长度
> */
> private static final int HEAD_LENGTH=9;
>
> /**
> * 系统统一的消息头两个字母
> */
> private static final String SIGN = "IC";
>
> /**
> * 加密解密工具类
> */
> private static BufferEncrypt encrypt =
> MahjongContext.getContext().getBean(BeanKey.BUFFERENCRYPT,
> BufferEncrypt.class) ;
>
> /**
> * 发送成功消息
> * @param channel 消息要发送的管道
> * @param cmdNum 命令号
> */
> public static ChannelFuture sendDefaultSuccessMessage(Channel channel,short
> cmdNum)
> {
> ChannelBuffer buf = writeHeader(cmdNum);
> buf.writeShort(DEFAULT_SUCCESS_MESSAGE);
> ChannelBuffer buffer = writeTail(buf,null);
> ChannelFuture future = channel.write(buffer);
> return future;
> }
>
> /**
> * 发送失败消息
> * @param channel 通道
> * @param errorCode 错误码
> * @param cmdNum 命令号
> */
> public static ChannelFuture sendFailureMessage(Channel channel, Integer
> errorCode,short cmdNum)
> {
> ChannelBuffer buf = writeHeader(cmdNum);
> buf.writeInt(errorCode);
> ChannelBuffer buffer = writeTail(buf,null);
> ChannelFuture future = channel.write(buffer);
> return future;
> }
>
> /**写头
> *
> * @param cmd 命令号
> * @return ChannelBuffer 装有header的buffer
> */
> public static ChannelBuffer writeHeader(short cmd) {
> LOGGER.debug("向前台发送命令:"+cmd);
> ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
> byte[] signBytes = SIGN.getBytes(Charset.forName("utf-8"));
> buf.writeBytes(signBytes);
> buf.writeShort(cmd);
> byte version = (byte)0;
> buf.writeByte(version);
> byte subVersion = (byte)0;
> buf.writeByte(subVersion);
> buf.writeByte(0);//body length 6
> buf.writeByte(0);//body length 7
> byte checkCode = (byte)0;
> buf.writeByte(checkCode);
> return buf;
> }
>
> /** 写头
> *
> * @param sign 头两个字母
> * @param cmd 命令号
> * @param version 主版本
> * @param subVersion 子版本
> * @return ChannelBuffer 装有header的buffer
> */
> @Deprecated
> public static ChannelBuffer writeHeader(String sign, short cmd, byte
> version, byte subVersion) {
> ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
>
> return buf ;
> }
>
> /**将Buffer重新整理,调整length field,使其正确
> *
> * @param buffer 整个包含头和内容的buffer
> * @return ChannelBuffer 整理
> */
> public static ChannelBuffer writeTail(ChannelBuffer buffer,Integer sig){
> if(null != sig)
> {
> buffer.writeInt(sig);
> }
>
> byte[] data = buffer.array();
> int length = data.length;
> int bodyLength = length - HEAD_LENGTH;
> buffer.setShort(6, (short)bodyLength);
> byte[] t = buffer.array();
> int bufferSize = t.length;
> t = encrypt.encryptBuffer(t,HEAD_LENGTH, bufferSize,
> BufferEncrypt.m_SendByteMap);
> ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
> buf.writeBytes(t);
> return buf;
> }
> }
>
> my spring bean is singleton
>
> thanks for Netty Forums.
> --
> View this message in context: http://netty-forums-and-mailing-lists.685743.n2.nabble.com/a-problem-in-my-app-Performance-Testing-tp5868665p5868665.html
> Sent from the Netty User Group mailing list archive at Nabble.com.
>
> _______________________________________________
> netty-users mailing list
> netty-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/netty-users
More information about the netty-users
mailing list