`
lianpeng0011
  • 浏览: 9111 次
社区版块
存档分类
最新评论

netty基础知识2

 
阅读更多

 本文所使用JDK7和netty5.0为基础。Netty5.0

 

Netty 服务端开发

      

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * Created by lianpeng on 2016/12/6.
 */
public class NettyService {

    private static final int PORT = 30088;

    public static void start() {
        //事件循环组将网络编程的线程处理部分很好的封装起来
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workGroup = new NioEventLoopGroup();
        //启动服务端必须实例化
        ServerBootstrap bootstrap = new ServerBootstrap();
        //指定使用的事件循环组,该组用于接受连接、接收/发送数据,等等
        //可以指定两个事件循环组,分别用于接受连接、读写数据
        bootstrap.group( bossGroup, workGroup )
                 //使用非阻塞的套接字传输,必须指定此服务器通道类型,以监听并处理客户端连接
                 .channel( NioServerSocketChannel.class )
                 //当连接被接受后,会创建NioServerSocketChannel的子通道SocketChannel
                 //childHandler方法用于指定子通道的处理器,通常为ChannelInitializer
                 .handler( new ChannelInitializer<SocketChannel>() {
                     @Override
                     protected void initChannel( SocketChannel ch ) throws Exception {
                         //管道(Pipeline)持有某个通道的全部处理器
                         ChannelPipeline pipeline = ch.pipeline();
                         //添加一个处理器
                         pipeline.addLast();
                     }
                 } );
        try {
            //绑定端口,等待直到成功
            ChannelFuture f = bootstrap.bind( PORT ).sync();
            //等待服务器通道被关闭
            f.channel().closeFuture().sync();
        } catch ( InterruptedException e ) {
            e.printStackTrace();
        } finally {
            //关闭事件循环,释放相关资源(包括创建的线程)
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }


}

class nettyServHandle extends ChannelHandlerAdapter {
    /**
     * 当从通道读取到数据后,会执行该回调
     * 注意:数据可能碎片化,分若干次读取,这种情况下,该回调会被执行多次
     */
    public void channelRead( ChannelHandlerContext ctx, Object msg ) {
        ByteBuf buf = (ByteBuf) msg;//注意这里不一定能收到完整的消息
        //将接收到的数据写回去,注意这里还没有将数据刷空以发送到对端(peer)
        //当前方法不使用channelRead0的原因:write可能在channelRead返回前尚未完成(因为异步)
        //如果使用channelRead0,那么msg对应的ByteBuf将被自动释放(release)
        ctx.write( msg );
    }

    /**
     * 当读取数据完毕(没有更多数据可读)后,会执行该回调
     */
    public void channelReadComplete( ChannelHandlerContext ctx ) {
        //刷空所有数据,并在执行完毕后,关闭通道
        ctx.writeAndFlush( Unpooled.EMPTY_BUFFER ).addListener( ChannelFutureListener.CLOSE );
    }

    /**
     * 当发生任何异常时,执行该回调
     * 至少应当有一个通道处理器覆盖此方法,以实现必要的异常处理
     */
    public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause ) {
        //关闭通道
        ctx.close();
    }
}

 

Netty 客户端开发

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.CharsetUtil;
 
import java.net.InetSocketAddress;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import cc.gmem.study.network.basic.Helper;
 
 
public class NettyClient
{
 
    private static final Logger LOGGER = LoggerFactory.getLogger( NettyClient.class );
 
    private final String        host;
 
    private final int           port;
 
    public NettyClient( String host, int port )
    {
        this.host = host;
        this.port = port;
    }
 
    public void start() throws Exception
    {
 
        EventLoopGroup group = new NioEventLoopGroup();
        try
        {
            //要启动客户端,必须实例化下面这个实例
            Bootstrap b = new Bootstrap();
            b
                    //指定事件循环组
                    .group( group )
                    //指定非阻塞的套接字通道类
                    .channel( NioSocketChannel.class )
                    //指定需要连接的服务器
                    .remoteAddress( new InetSocketAddress( host, port ) )
                    //指定通道的处理器,一旦连接成功就会调用此处理器
                    .handler( new ChannelInitializer() {
 
                        public void initChannel( SocketChannel ch ) throws Exception
                        {
                            //在通道的尾部添加一个处理器
                            ch.pipeline().addLast( new EchoClientHandler() );
                        }
                    } );
            //连接、等待直到连接成功
            ChannelFuture f = b.connect().sync();
            //等待直到客户端通道被关闭
            f.channel().closeFuture().sync();
        }
        finally
        {
            //关闭事件循环,释放相关资源(包括创建的线程)
            group.shutdownGracefully().sync();
        }
    }
 
    public static void main( String[] args ) throws Exception
    {
        new EchoClient( Helper.DEFAULT_HOST, Helper.DEFAULT_PORT ).start();
    }
 
    @Sharable
    public class NettyClientHandler extends SimpleChannelInboundHandler
    {
 
        /**
         * 一旦与服务器的连接建立,即调用此回调
         */
        public void channelActive( ChannelHandlerContext ctx )
        {
            //发送一个简单的消息给服务器
            //Unpooled是一个工具类,可以分配新的缓冲,或者包装已经存在的字节数组、字节缓冲、字符串
            //copiedBuffer方法可以根据指定的字符串和编码方式,创建一个大端(big-endian)的字节缓冲
            //这里的几个汉字和标点共计21字节
            ByteBuf msg = Unpooled.copiedBuffer( "服务器,你好!", CharsetUtil.UTF_8 );
            //写入数据并刷空,如果不刷空,数据可能存在于本地缓冲,不发送给服务器
            ctx.writeAndFlush( msg );
        }
 
        /**
         * 从服务器接收到数据后,调用此回调。channelRead0会自动的释放(减少引用计数,如果为0则解构并回收)ByteBuf对象
         * 需要注意的是:接收到的字节可能是碎片化的(channelRead0),虽然上面发送了21字节给服务器
         * 但是可能分多次读取,例如:第一次读取10字节,第二次读取11字节。因此该回调可能被调用多次
         * 唯一能保证的是:在使用TCP或其它面向流的协议的情况下,数据被读取的顺序有保证
         */
        public void channelRead0( ChannelHandlerContext ctx, ByteBuf in )
        {
            int count = in.readableBytes();//可以获取本次可读的字节数
            ByteBuf buf = in.readBytes( count ); //读取为字节缓冲
            Object msg = buf.toString( CharsetUtil.UTF_8 );//转换为字符串形式
            LOGGER.debug( "Client received: {}", msg );
        }
 
        public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause )
        {
            ctx.close();
        }
    }
}

 

Netty 解决tcp粘包和分包

   TCP以流的方式进行数据传输,上层的应用程序为了对消息进行区分,往往采样一下此种方式

  1.消息长度固定,累计读取到长度总和为LEN的报文后,就认为读取到了一个完整的消息;讲计数器,讲计数器职位重新开始读下一个数据包;

  2.将回车符作为消息的结束符,例如:FTP协议,这种方式使用比较广泛

  3.将特殊字符作为消息的结束符;

  4.通过消息头定义长度字段来标示消息的总长度。

Netty对上面四种应用做了统一的抽象,提供了四种解码器来解决对应问题。

   1. StringDecoder     将消息解码成String类型方便读取;

    2.LineBasedFrameDecoder    以换行符为结束标记的解码器,工作原理是依次遍历ByteBuf中的可读字节,判读是否是“\n”或“\r\n”;

pipeline.addLast(new LineBasedFrameDecoder( 1024 ) );

    3.DelimiterBasedFrameDecoder   以特殊字符为消息结束符的解码器;

 

ByteBuf delimiter = Unpooled.copiedBuffer( "$_".getBytes() );
//第一个参数表示消息的最大长度,当消息读取到最大长度后任然没找见分割符,就抛出
//TooLongFrameException异常,防止异常码流缺失导致的内存溢出
pipeline.addLast( "framer", new DelimiterBasedFrameDecoder( Integer.MAX_VALUE, Delimiters.nulDelimiter() ) );

   4.FixedBasedFrameDecoder   以固定长度进行解码,不管一次接受多少数据包,他都是按设定的长度进行解码;

    

pipeline.addLast( new FixedBasedFrameDecoder( 1024 ) );

 

 

 

 

 

 

分享到:
评论

相关推荐

    Netty 基础知识点学习汇总

    设计基础知识,初学者可以参照

    unit3.2.rar netty基础类netty基础类netty基础类netty基础类netty基础类

    本节我们将深入探讨Netty的基础类和核心概念,帮助你构建坚实的Netty知识体系。 1. **ByteBuf**: Netty中的核心数据结构是`ByteBuf`,它是Java NIO `ByteBuffer`的增强版。`ByteBuf`提供了更高效的内存管理,支持...

    Netty权威指南 第2版 带书签目录 完整版

    内容不仅包含Java NIO入门知识、Netty 的基础功能开发指导、编解码框架定制等,还包括私有协议栈定制和开发、Netty 核心类库源码分析,以及Netty 的架构剖析。 《Netty 权威指南(第2 版)》适合架构师、设计师、...

    Netty实战.epub_netty实战epub_netty实战epub_netty_

    总的来说,《Netty实战》这本书全面覆盖了Netty的基础到高级知识,通过实例教学,使读者能够深入理解Netty的工作原理,并具备使用Netty构建高性能网络应用的能力。对于想要提升Java网络编程技能,或者已经在使用...

    Netty 教程 Netty权威指南

    总之,《Netty 权威指南》507页的完整版教程将深入探讨这些知识点,并通过实例帮助读者掌握如何在实际项目中运用 Netty 构建高效稳定的网络应用。通过学习,你可以深入了解 Netty 的设计理念,熟练运用其高级特性和...

    跟闪电侠学Netty:Netty即时聊天实战与底层原理-book-netty.zip

    2. **Netty架构**:Netty采用了反应器模式,包含Bootstrap(引导类)、ServerBootstrap(服务器引导类)、Channel(通道)、EventLoop(事件循环)、Pipeline(处理链)等组件,构建了高效的事件驱动模型。...

    netty官网学习手册中文版

    这个“netty官网学习手册中文版”针对的是Netty的3.1版本,虽然现在的Netty已经发展到了5.x版本,但3.1版本的知识仍然具有历史参考价值,特别是对于那些初次接触或需要理解Netty基础概念的开发者来说。 1. **Netty...

    Netty权威指南 第2版 带书签目录 高清完整版.pdf

    内容不仅包含Java NIO入门知识、Netty 的基础功能开发指导、编解码框架定制等,还包括私有协议栈定制和开发、Netty 核心类库源码分析,以及Netty 的架构剖析。 《Netty 权威指南(第2 版)》适合架构师、设计师、...

    Netty权威指南(第2版)

    内容不仅包含Java NIO入门知识、Netty 的基础功能开发指导、编解码框架定制等,还包括私有协议栈定制和开发、Netty 核心类库源码分析,以及Netty 的架构剖析。 《Netty 权威指南(第2 版)》适合架构师、设计师、...

    netty 权威指南2 源码

    总的来说,《Netty 权威指南2》的源码部分会涉及网络编程基础、并发模型、内存管理、协议处理等多个方面的知识,是一份深入学习和研究Netty不可多得的资料。通过深入学习,开发者不仅能掌握Netty的使用,还能具备...

    Netty权威指南 第2版 + 源码

    1. **NIO基础**:Netty基于Java的非阻塞I/O(NIO)模型构建,它允许在网络通信中实现高效的读写操作,同时处理多个连接,显著提高了系统的并发能力。 2. **ByteBuf**:Netty的ByteBuf是线程安全的字节缓冲区,提供...

    Netty权威指南第二版

    内容不仅包含Java NIO入门知识、Netty 的基础功能开发指导、编解码框架定制等,还包括私有协议栈定制和开发、Netty 核心类库源码分析,以及Netty 的架构剖析。 《Netty 权威指南(第2 版)》适合架构师、设计师、...

    NETTY权威指南(第2版)pdf

    - Netty基础:介绍Netty的基本架构,包括Bootstrap、ServerBootstrap、Channel、EventLoopGroup等关键概念。 - 异步编程:解释Netty的事件驱动模型和异步处理机制。 - 编解码:详细讲解Netty的编码器和解码器,以及...

    netty in action(中英版) netty权威指南(第1,2版)

    Netty的Channel接口是整个框架的基础,代表了一个打开的连接或者一个可以读写数据的通道。 在《Netty权威指南》中,读者会了解到如何使用ChannelHandler进行事件处理。ChannelHandler是Netty中的核心组件,负责处理...

    Netty权威指南高清版本

    首先,Netty的基础知识包括了NIO(非阻塞I/O)的概念。NIO在Java中提供了一种不同于传统阻塞I/O的I/O模型,它允许多个连接并行处理,而非在一个连接上等待数据读写完成。Netty充分利用了NIO的特性,实现了高效的网络...

    Netty权威指南pdf+源代码

    书中的章节涵盖了Netty的基础知识,包括IO模型、NIO基础、缓冲区管理、线程模型、编码与解码、管道处理、以及Netty的高级特性等。通过学习这些章节,开发者可以理解Netty如何优化网络通信,提升系统性能。 Netty的...

    Netty权威指南 第2版 完整版

    Netty的基础知识包括以下几个方面: 1. **Java NIO基础**:Netty是基于Java NIO(非阻塞I/O)构建的,NIO提供了一种不同于传统阻塞I/O的I/O模型。它支持多路复用,允许一个线程同时处理多个连接,提高了系统的并发...

    Netty权威指南 第2版 带书签目录 完整版.pdf

    书中第一部分主要围绕Netty的基础知识进行讲解,包括Netty的概览、核心组件以及核心编解码器的使用方法,另外也对Netty的高性能特点做了详细说明。第二部分则深入到了Netty的内部原理,包括Netty的启动流程、核心...

    Netty实战-Netty.zip

    在深入探讨Netty的知识点之前,我们先简单理解一下什么是框架。框架是一种半成品软件,它提供了标准的结构和模式,开发者可以在其基础上进行定制化开发,以满足特定应用的需求。 Netty 的核心特性包括: 1. **异步...

Global site tag (gtag.js) - Google Analytics