Netty笔记

Netty简介:

      Netty 是一个异步的,事件驱动的网络编程框架和工具,使用Netty 可以快速开发出可维护的,高性能、高扩展能力的协议服务及其客户端应用。也就是说,Netty 是一个基于NIO的客户,服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。

基本的NettyApi:

     定义客户端处理类, 继承ChannelHandlerAdapter,

      这个类实现了ChannelHandler接口,ChannelHandler提供了许多事件处理的接口方法,然后你可以覆盖这些方法。现在仅仅只需要继承ChannelHandlerAdapter类而不是你自己去实现接口方法。

public class ClientHandler extends ChannelHandlerAdapter {
 
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg)
            throws Exception {
        try {
            // do something msg
            ByteBuf buf = (ByteBuf) msg;
            byte []data=new byte[buf.readableBytes()];
            buf.readBytes(data);
            String request = new String(data, "utf-8");
            System.out.println("Client: " + request);
 
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }
 
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
 
}

客户端:

publicclass Client {
 
   publicstaticvoid main(String[] args) throws InterruptedException {
 
      EventLoopGroup workgroup = new NioEventLoopGroup();
      Bootstrap b = new Bootstrap();
      b.group(workgroup).channel(NioSocketChannel.class)
           .handler(new ChannelInitializer<SocketChannel>() {
              @Override
              protectedvoid initChannel(SocketChannel sc)
                    throws Exception {
                 sc.pipeline().addLast(new ClientHandler());
              }
           });
      // 发送消息
      ChannelFuture cf1 = b.connect("127.0.0.1", 8765).sync();
      // 发送给服务端数据
   cf1.channel().writeAndFlush(Unpooled.copiedBuffer("hi netty ".getBytes()));
//强烈建议发送的是Buffer类型的。因为netty涉及到一些解析器,解析是Buffer类型的数据。
 
      cf1.channel().closeFuture().sync();
      workgroup.shutdownGracefully();
   }
}

服务端:

publicclass Server {
  
   publicstaticvoid main(String[] args) throws Exception {
     
      EventLoopGroup bossGroup=new NioEventLoopGroup();
     
      EventLoopGroup workerGroup=new NioEventLoopGroup();
     
      ServerBootstrap serverBootstrap=new ServerBootstrap();
      serverBootstrap.group(bossGroup,workerGroup);
      serverBootstrap.channel(NioServerSocketChannel.class); //通道
      serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>(){
 
        @Override
        protectedvoid initChannel(SocketChannel ch) throws Exception {
           //ch.pipeline().addLast(new FixedLengthFrameDecoder(5)); //5 表示5个长度;
           //ch.pipeline().addLast(new StringDecoder());  字符串解码器(StringDecoder)将缓存(buffer)解码为字符串
           ch.pipeline().addLast(new ServerHandler());
        }
      } );
      serverBootstrap.option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true); ;         // (5)
      ChannelFuture f = serverBootstrap.bind(8765).sync();
     
      f.channel().closeFuture().sync();
     
      workerGroup.shutdownGracefully();
 
      bossGroup.shutdownGracefully();
 
   }
 
}

ServerHandler:

publicclass ServerHandler extends ChannelHandlerAdapter {
 
   @Override
   publicvoid channelRead(ChannelHandlerContext ctx, Object msg)
        throws Exception {
 
      // do something msg
      ByteBuf buf = (ByteBuf) msg;
      byte[] data = newbyte[buf.readableBytes()];
      buf.readBytes(data);
      String request = new String(data, "utf-8");
      System.out.println("Server: " + request);
      // 写给客户端
      //ctx.write(Object)方法不会使消息写入到通道上,他被缓冲在了内部,你需要调用ctx.flush()方法来把缓冲区中数据强行输出。
      //或者你可以用更简洁的cxt.writeAndFlush(msg)以达到同样的目的。
       //f.addListener(ChannelFutureListener.CLOSE);   用来在操作完成时关闭客户端 Channel
       ChannelFuture f = ctx.writeAndFlush(Unpooled.copiedBuffer("888".getBytes()));
//强烈建议发送的是Buffer类型的。因为netty涉及到一些解析器,解析是Buffer类型的数据。
       //writeAndFlush 不需要释放消息资源,底层自动帮你释放。
   }
 
   @Override
   publicvoid exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
        throws Exception {
      cause.printStackTrace();
      ctx.close();
   }
 
}

// 发送消息

ChannelFuture cf1 = b.connect("127.0.0.1", 8765).sync();

// buf

cf1.channel().writeAndFlush(Unpooled.copiedBuffer("hi netty ".getBytes())); 

 

TCP 粘包和拆包问题:

      TCP网络传输是基于流的形式传输,所谓的流是没有界限的遗传数据,好比河里的水,是没有断续的,TCP底层

并不了解上层业务数据的具体含义,它会根据TCP缓存区的实际情况进行包的划分,也就是说,在业务上,

我们一个完整的包可能会被TCP分成多个包的形式进行发送,也可将多个小包封装成一个大的数据包发送出去,

这就是所谓的 TCP 粘包和拆包。

 

解决方式:

   (1)消息长度固定,累计读取到长度总和为定长LEN 的报文后,就认为读取到了一个完整的消息,将计数器置位,重新开始读取下一个数据报;例如每个报文的大小固定为200个字节,如果不够,空位补空格。

   (2)将回车换行符作为消息结束符,例如FTP协议,这种方式在文本协议中应用比较广泛:

   (3)将特殊的分隔符作为消息的结束标志,回车换行符就是一种特殊的结束分隔符:

   (4)通过在消息头中定义长度字段来标识消息的总长度。

   (5)自定义协议,携带消息头消息体,在消息头中包含表示消息总长度的字段,然后进行业务逻辑处理。

 

Netty对以上四种应用做了统一的抽象,提供了4种解码器来解决对应的问题,,分别是:

   LineBasedFrameDecoder      换行符

   DelimiterBaseFrameDecoder  自动完成以分隔符做结束标志的消息的解码  

        http://blog.csdn.net/upup918/article/details/47864933

    FixdLengthFrameDecoder     自动完成对定长消息的解码

LineBasedFrameDecoder 主要代码演示:

    ch.pipeline().addLast(new LineBasedFrameDecoder(1024)); 

    ch.pipeline().addLast(new StringDecoder()); 

  

DelimiterBaseFrameDecoder 主要代码演示:

   ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());

   ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,delimiter));

   ch.pipeline().addLast(new StringDecoder());

   ch.pipeline().addLast(new EchoClientHandler());

  

FixdLengthFrameDecoder 主要代码演示:

       ch.pipeline().addLast(new FixedLengthFrameDecoder(5)); //5 表示5个长度; 如:客户端输入“aaaaaa” —> 服务端 只会接收到 “aaaaa” ; 所以数据实在不够的时候 以空位补空格。

   

 

 常用的使用场景:


 Netty 自定义协议方式:

   http://blog.csdn.net/zbw18297786698/article/details/53691915


 Netty编解码技术(序列化技术):

     http://blog.csdn.net/wodeyuer125/article/details/44495549  序列化技术技术对比;

 

  Netty Marshalling 编解码方式:

       http://www.itnose.net/detail/6112870.html

 

基于Netty 实现心跳包服务、断开重连:

   基于   IdleStateHandler ;

   http://blog.csdn.net/linuu/article/details/51509847


基于Netty 的文件传输与下载;

  https://github.com/LWHTarena/netty


基于Netty的WEBSOCK编程;

 http://blog.csdn.net/u010739551/article/details/51423538


Netty学习:

     http://ifeve.com/netty5-user-guide/ 

     http://www.itstack.org/?sort=9

      http://blog.csdn.net/column/details/enjoynetty.html


发表评论