网状。服务器在向所有客户端发送数据时抛出异常

时间:2015-02-11 17:21:42

标签: netty

哟。我想创建简单的服务器。当客户端连接时 - 其频道已添加到频道列表中。当服务器从某个客户端接收消息时,消息将发送给所有客户端。 如果有一个客户端和服务器向该客户端发送消息 - 一切都没问题。但是如果有两个客户端 - 在发送消息后,Netty会抛出异常。 这是我的所有代码

主要初始化程序

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import io.netty.channel.socket.SocketChannel;

public class Main {

    public static GameLogic gameLogic;

    public void StartServer() throws Exception
    {
        gameLogic=new GameLogic(4);

        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch)
                        {
                            ch.pipeline().addLast(new ConnectionHandler()).addLast(new FrameHandler()).addLast(new PacketHandler());
                        }
                    }).option(ChannelOption.SO_BACKLOG,128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture f = b.bind(50000).sync();

            f.channel().closeFuture().sync();
        }
        finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception{
        new Main().StartServer();
    }

}

连接处理程序:

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.Channel;

import java.util.concurrent.CopyOnWriteArrayList;

public class ConnectionHandler extends ChannelInboundHandlerAdapter {

    public static CopyOnWriteArrayList<Channel> clients=new CopyOnWriteArrayList<Channel>();

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Channel ch=ctx.channel();
        if(!clients.contains(ch))
        {
            clients.add(ch);
        }
        System.out.println("Got client");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel ch = ctx.channel();
        if(clients.contains(ch))
        {
            clients.remove(ch);
        }
        System.out.println("Lost client");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable throwable) throws Exception {
        System.out.println(throwable.getMessage());
    }
}

帧处理程序:

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.nio.ByteOrder;
import java.util.List;

public class FrameHandler extends ByteToMessageDecoder {

    int packetLength=0;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        if (in.readableBytes() < 4) {
            return;
        }
        else if(packetLength==0)
        {
            packetLength=in.order(ByteOrder.LITTLE_ENDIAN).getInt(0);
            in.readerIndex(4);
            System.out.println("length: "+packetLength);
        }
        else if(in.readableBytes()<packetLength)
        {
            return;
        }
        out.add(in.readBytes(packetLength));
        packetLength=0;
        System.out.println("added");
    }
}

数据包处理程序:

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;


public class PacketHandler extends ChannelInboundHandlerAdapter {

    private Session session;

    public PacketHandler()
    {
        System.out.println("PacketHandler!");
        session=new Session();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buff = (ByteBuf)msg;
        System.out.println("Got "+buff.readableBytes()+" bytes");

        Packet packet = new Packet(buff);
        session.addToReadQueue(packet);
        Main.gameLogic.addSessionToQueue(session);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
    }
}

数据包类:

import io.netty.buffer.ByteBuf;

public class Packet {
    private ByteBuf data;

    public Packet(ByteBuf data)
    {
        this.data=data;
    }

    public ByteBuf getData()
    {
        return data;
    }
}

会话班:

import java.util.concurrent.LinkedBlockingQueue;

public class Session {
    private LinkedBlockingQueue<Packet> readQueue;
    private LinkedBlockingQueue<Packet> writeQueue;

    public Session()
    {
        readQueue=new LinkedBlockingQueue<Packet>();
        writeQueue=new LinkedBlockingQueue<Packet>();
    }

    public void addToReadQueue(Packet packet)
    {
        readQueue.add(packet);
    }

    public void addToWriteQueue(Packet packet)
    {
        writeQueue.add(packet);
    }

    public Packet takeFromReadQueue() throws Exception
    {
        return readQueue.take();
    }

    public Packet takeFromWriteQueue() throws Exception
    {
        return writeQueue.take();
    }
}

GameLogic类:

import com.fasterxml.jackson.databind.ObjectMapper;
import de.undercouch.bson4jackson.BsonFactory;

import java.io.ByteArrayInputStream;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import io.netty.channel.Channel;

public class GameLogic implements Runnable {

    private final BlockingQueue<Session> sessionQueue;
    private final ExecutorService threadPool;
    private int threadPoolSize;

    public GameLogic(int threadPoolSize)
    {
        this.threadPoolSize=threadPoolSize;
        this.threadPool= Executors.newFixedThreadPool(threadPoolSize);
        this.sessionQueue=new LinkedBlockingQueue<Session>();

        initThreadPool();
    }

    private void initThreadPool()
    {
        for(int i=0; i<this.threadPoolSize; i++)
        {
            this.threadPool.execute(this);
        }
    }

    public void addSessionToQueue(Session session)
    {
        if(session!=null)
        {
            this.sessionQueue.add(session);
        }
    }

    @Override
    public void run() {
        while (true)
        {
            try
            {
                Session session = this.sessionQueue.take();
                Packet packet = session.takeFromReadQueue();
                ObjectMapper mapper = new ObjectMapper(new BsonFactory());
                ByteArrayInputStream bais = new ByteArrayInputStream(packet.getData().array());
                GeneralMessage message1 = mapper.readValue(bais,GeneralMessage.class);

                JsonMessage message = (JsonMessage)message1;
                System.out.println("Name = "+message.getName()+"  ID = "+message.getId());

                for(Channel ch : ConnectionHandler.clients)
                {
                    ch.writeAndFlush(packet.getData());
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }
}

以下是两个例外情况的文字。我在第一个客户端连接并发送消息时得到的第一个例外,然后第二个客户端连接并发送消息。 第二个异常我连接两个客户端时没有发送消息,然后一个客户端发送消息。

2015 7:10:13 PM io.netty.channel.AbstractChannelHandlerContext notifyOutboundHandlerException
WARNING: Failed to fail the promise because it's done already: DefaultChannelPromise@633c2a46(failure(io.netty.util.IllegalReferenceCountException: refCnt: 0)
io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:101)
    at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:59)
    at io.netty.channel.AbstractChannel$AbstractUnsafe.write(AbstractChannel.java:670)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.write(DefaultChannelPipeline.java:1113)
    at io.netty.channel.AbstractChannelHandlerContext.invokeWrite(AbstractChannelHandlerContext.java:633)
    at io.netty.channel.AbstractChannelHandlerContext.access$1900(AbstractChannelHandlerContext.java:32)
    at io.netty.channel.AbstractChannelHandlerContext$AbstractWriteTask.write(AbstractChannelHandlerContext.java:908)
    at io.netty.channel.AbstractChannelHandlerContext$WriteAndFlushTask.write(AbstractChannelHandlerContext.java:960)
    at io.netty.channel.AbstractChannelHandlerContext$AbstractWriteTask.run(AbstractChannelHandlerContext.java:893)
    at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:380)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)
    at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
    at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
    at java.lang.Thread.run(Thread.java:744)
2015 7:17:57 PM io.netty.util.ReferenceCountUtil safeRelease
WARNING: Failed to release a message: UnpooledHeapByteBuf(freed)
io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:101)
    at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:59)
    at io.netty.util.ReferenceCountUtil.safeRelease(ReferenceCountUtil.java:84)
    at io.netty.channel.nio.AbstractNioChannel.newDirectBuffer(AbstractNioChannel.java:403)
    at io.netty.channel.nio.AbstractNioByteChannel.filterOutboundMessage(AbstractNioByteChannel.java:273)
    at io.netty.channel.AbstractChannel$AbstractUnsafe.write(AbstractChannel.java:663)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.write(DefaultChannelPipeline.java:1113)
    at io.netty.channel.AbstractChannelHandlerContext.invokeWrite(AbstractChannelHandlerContext.java:633)
    at io.netty.channel.AbstractChannelHandlerContext.access$1900(AbstractChannelHandlerContext.java:32)
    at io.netty.channel.AbstractChannelHandlerContext$AbstractWriteTask.write(AbstractChannelHandlerContext.java:908)
    at io.netty.channel.AbstractChannelHandlerContext$WriteAndFlushTask.write(AbstractChannelHandlerContext.java:960)
    at io.netty.channel.AbstractChannelHandlerContext$AbstractWriteTask.run(AbstractChannelHandlerContext.java:893)
    at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:380)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)
    at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
    at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
    at java.lang.Thread.run(Thread.java:744)

那么如何解决呢?我不知道为什么会出现异常。

0 个答案:

没有答案