隨筆-95  評論-31  文章-10  trackbacks-0
          netty從4.x開始,已經不再是jboss的一部分,所以引包中,發現還有org.jboss.netty.*等字樣說明你還用的是3.x即以下版本,現在已經到5.0了該更新了,新的包名統一為io.netty.*開頭
          5.0以后內容:
              netty初體驗,netty是個高性能的java通信框架,至于oio還是nio,它都支持,核心概念:基于事件驅動的架構,很容易讓人聯想到觀察者模式。它提供的數據結構為ByteBuf,這個是個什么東西?可以理解為:一個數據的載體,比如我接收和發送的消息,得到的都是ByteBuf對象,它是對字節流的一個高度抽象化,并提供比NIO的ByteBuffer更多的功能,不至于同一個buffer中經常操作,flip,compact等方法,更為簡潔實用,同時如果客戶端和服務端都采用java,那么它也可以提供自定義的object類型的數據載體。netty官方提供的example很多,客戶端和服務端如何寫,照貓畫虎即可。
              把握住兩個關鍵點即可:*handler和傳遞的內容(即發送和接收的消息),*handler里面包含具體事件的觸發方法:比如exceptionCaught方法(出現異常時)、messageReceived方法(接收消息時)、channelActive(連接剛建立時)等方法,采用最新的SimpleChannelInboundHandler<T> 這個handler,T可以為自定義的任何對象,如果不需要自定義對象,那么傳遞Object即可,如果是自定義對象或者java基本類型或String類型,那么必須得有個大前提:客戶端和服務端都必須得進行一定的轉換,換句話說:我的客戶端和服務端必須都得用netty的相關API封裝一次(具體看netty例子)。如果不是自定義對象,而傳遞的是Object,那么在收到消息時,必須進行強制轉換為ByteBuf對象,通過ChannelHandlerContext進行發送,這個時候發送的是ByteBuf對象,如果是自定義對象,那么ChannelHandlerContext.write(自定義對象)即可,同時必須調用flush方法才能發送出去,也可調用wirteAndFlush(自定義對象)方法。
               
              深究了兩天netty,得出的結論是:如果客戶端和服務端都基于netty,那么互發消息,各種類型協議消息,基本都不成問題。官方example很多,照貓畫虎,自定義隨便玩
              但是,如果我只用netty的服務端,而客戶端是一個純粹的socket,比如其它語言的客戶端,比如純粹只是一個硬件,進行socket連接等等,即不采用netty的API,而且不是java語言,那么就會有一些問題。
              
              首先我用java的oio和nio寫了2個極其簡單的客戶端不使用netty,同時netty服務端要給返回響應,先看兩個極其簡單的客戶端代碼:
           1//首先oio客戶端
           2    public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException {
           3        Socket socket = new Socket("127.0.0.1",8080);
           4        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
           5        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
           6        bw.write("hello world!");
           7        bw.flush();
           8        
           9        while(true){
          10            String str = br.readLine();
          11            System.out.println(str);
                            Thread.sleep(2000);
                          }
          12 }
           1//其次nio客戶端,其實也可改成阻塞,效果一樣
           2public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException {
           3        
           4        SocketChannel socket = SocketChannel.open();
           5        boolean status = socket.connect(new InetSocketAddress("127.0.0.1",8080) );
           6        System.out.println(status);
           7        socket.configureBlocking(false);
           8//        Selector selection = Selector.open();
           9        String msg = "hello world!";
          10        ByteBuffer buffer = ByteBuffer.allocate(msg.getBytes().length);
          11        buffer.put(msg.getBytes());
          12        buffer.flip();
          13        socket.write(buffer);
          14        buffer.compact();
          15        
          16        
          17        
          18        Thread.sleep(1000000);
          19    }

          netty服務端的handler是DiscardServerHandler extends SimpleChannelInboundHandler<Object> 里面的messageReceived方法
           1    @Override
           2    public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
           3        // discard
           4        ByteBuf buffer = (ByteBuf) msg;
           5        byte[] bytes = new byte[buffer.readableBytes()];
           6        System.out.println("readableBytes="+buffer.readableBytes());
           7        buffer.readBytes(bytes);
           8        String str = new String(bytes);
           9        logger.info("=========="+str+"==============");
          10        
          11        boolean close =false;
          12        if(str.equals("bye")){
          13            close = true;
          14        }

          15        
          16        System.out.println("buffer capacity="+buffer.capacity() +"  str length="+str.length()
          17                +"readableBytes="+buffer.readableBytes());
          18        String str1 = "hi I'am server this is my info : @111111@";
          19        buffer.writeBytes(str1.getBytes());
          20        ctx.writeAndFlush(buffer);
          21//        ChannelFuture future = ctx.writeAndFlush(buffer);
          22
          23        // Close the connection after sending 'Have a good day!'
          24        // if the client has sent 'bye'.
          25//        if (close) {
          26//            future.addListener(ChannelFutureListener.CLOSE);
          27//        }
          28    }    

          服務端,客戶端也能收到消息,但服務端拋出以下異常:

          警告: Unexpected exception from downstream.
          io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
          at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:115)
          at io.netty.buffer.WrappedByteBuf.release(WrappedByteBuf.java:819)
          at io.netty.buffer.SimpleLeakAwareByteBuf.release(SimpleLeakAwareByteBuf.java:34)
          at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:68)
          at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:110)
          at io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:74)
          at io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:138)
          at io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:320)
          at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:846)
          at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:127)
          at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:485)
          at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:452)
          at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:346)
          at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:794)
          at java.lang.Thread.run(Unknown Source)


          原因是:refCnt=0了,表明使用的這個ByteBuf已經被回收了,代碼中調用ctx.writeAndFlush(buff)會使此次ByteBuf回收也即將refCnt置為0,那么在SimpleChannelInboundHandler里面,會接著調用代碼如下:
           1    @Override
           2    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
           3        boolean release = true;
           4        try {
           5            if (acceptInboundMessage(msg)) {
           6                @SuppressWarnings("unchecked")
           7                I imsg = (I) msg;
           8                messageReceived(ctx, imsg);
           9            }
           else {
          10                release = false;
          11                ctx.fireChannelRead(msg);
          12            }

          13        }
           finally {
          14            if (autoRelease && release) {
          15                ReferenceCountUtil.release(msg);
          16            }

          17        }

          18    }

          里面的15行ReferenceCountUtil.release(msg);這是netty提供的一個釋放ByteBuf內存的方法,如果不采用這個,直接調用ByteBuf.release方法也可以,但是因為調用了writeAndFlush方法,已經將ByteBuf的refCnt置為0了,這個里面調用的時候又會在設置一次,但是發現已經為0了,所以就拋出的該異常。
          該問題需要在定位。。。。未完待續
          posted on 2014-05-03 14:11 朔望魔刃 閱讀(5468) 評論(0)  編輯  收藏 所屬分類: netty

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          <2014年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          常用鏈接

          留言簿

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          收藏夾

          娛樂博客

          牛博

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 南通市| 沙河市| 益阳市| 阿巴嘎旗| 鄱阳县| 阜宁县| 江口县| 东阳市| 石屏县| 当涂县| 高要市| 宝清县| 武义县| 德清县| 余江县| 宜都市| 綦江县| 金塔县| 吐鲁番市| 环江| 桦甸市| 顺平县| 霸州市| 伊金霍洛旗| 灵丘县| 丹寨县| 宜丰县| 鲁甸县| 永丰县| 庆阳市| 莲花县| 饶平县| 启东市| 荆门市| 迭部县| 德惠市| 商水县| 阿克陶县| 大庆市| 宿迁市| 金华市|