哟。我想创建简单的服务器。当客户端连接时 - 其频道已添加到频道列表中。当服务器从某个客户端接收消息时,消息将发送给所有客户端。 如果有一个客户端和服务器向该客户端发送消息 - 一切都没问题。但是如果有两个客户端 - 在发送消息后,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)
那么如何解决呢?我不知道为什么会出现异常。