最近在研究和学习Netty,按照书上的教程写了一个很简单的demo,但是运行却报错了,代码如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
package com.fan3cn.netty; import java.net.InetSocketAddress; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; public class TestDemo { //端口号 private static int port = 7777; public static void main(String[] args) { // TODO Auto-generated method stub TestDemo testDemo = new TestDemo(); testDemo.startup(); } public void startup(){ ServerBootstrap sb = new ServerBootstrap(); sb.group(new NioEventLoopGroup(), new NioEventLoopGroup()); sb.channel(NioServerSocketChannel.class); sb.childHandler(new MySimpleChannelInboundHandler()); ChannelFuture future = sb.bind(new InetSocketAddress(port)); future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture f) throws Exception { // TODO Auto-generated method stub if(f.isSuccess()){ System.out.println("bind success,listening on "+port); }else{ System.out.println("bind failed"); } } }); } /** * handler * @author Eric * */ public class MySimpleChannelInboundHandler extends SimpleChannelInboundHandler<ByteBuf>{ @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf data) throws Exception { // TODO Auto-generated method stub int readIdx = data.readableBytes(); byte[] bytes = data.readBytes(readIdx).array(); String msg = new String(bytes); System.out.println("recevied data:\n"+msg); } } } |
启动好了之后,浏览器输入:http://127.0.0.1:7777?x=1&y=2 ,但是令人奇怪的是这个服务器只能接受一次请求,后面的请求均会产生如下的报错:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Oct 24, 2016 9:52:41 PM io.netty.channel.DefaultChannelPipeline$TailHandler exceptionCaught WARNING: An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception. io.netty.channel.ChannelPipelineException: com.fan3cn.netty.TestDemo$MySimpleChannelInboundHandler is not a @Sharable handler, so can't be added or removed multiple times. at io.netty.channel.DefaultChannelPipeline.checkMultiplicity(DefaultChannelPipeline.java:461) at io.netty.channel.DefaultChannelPipeline.addLast0(DefaultChannelPipeline.java:138) at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:131) at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:258) at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:245) at io.netty.bootstrap.ServerBootstrap$ServerBootstrapAcceptor.channelRead(ServerBootstrap.java:232) at io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:372) at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:357) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:780) at io.netty.channel.nio.AbstractNioMessageChannel$NioMessageUnsafe.read(AbstractNioMessageChannel.java:87) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:497) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:465) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:359) at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101) at java.lang.Thread.run(Thread.java:745) |
按照报错的提示,原因就是这个channelHandler没有使用@Shareable注解,加上之后果然问题解决了。但是到这里我的疑问并没有得到解决,为什么这个handler必须要加上@Shareable注解?这一步步到底是怎么回事?经过几次断点,再结合阅读源码,总算是搞清楚为什么了。
首先来看抛出异常的方法DefaultChannelPipeline->checkMultiplicity,代码如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
private static void checkMultiplicity(ChannelHandlerContext ctx) { ChannelHandler handler = ctx.handler(); if (handler instanceof ChannelHandlerAdapter) { ChannelHandlerAdapter h = (ChannelHandlerAdapter) handler; if (!h.isSharable() && h.added) { throw new ChannelPipelineException( h.getClass().getName() + " is not a @Sharable handler, so can't be added or removed multiple times."); } h.added = true; } } |
这段代码很简单,如果这个handler被加过了,也就是h.adder=true,并且不是[……]