7.Netty

Netty
    介绍:是一个NIO client-server(客户端服务器)框架,使用Netty可以快速开发网络应用,它提供了
           简单易用的api从网络处理代码中解耦业务逻辑。Netty完全基于NIO实现的,Netty是异步的。
    
    Netty健壮性、功能、性能、可定制性和可扩展性在同类框架都是首屈一指的。
    
    网站:http://ifeve.com/netty5-user-guide/
    
    Netty实现通信的步骤:
        1:创建两个NIO线程组,一个用于网络事件处理(接受客户端的连接),另一个则进行网络
          通信的读写。
        2:创建一个ServerBootstarp对象,配置Netty的一系列参数,如传出去数据的缓存
        3:创建一个实际处理数据的类ChannelInitializer,进行初始化的准备工作,比如设置接受传出
          数据的字符集、格式、已经实际处理数据的接口
        4:绑定端口,执行同步阻塞方法等待服务器端口启动即可
    
    Netty对Byte实现了优化,因为有两个指针
    
    TCP粘包、拆包问题
        1、应用程序write写入的字节大小大于套接口发送缓冲区的大小
        2、进行MSS大小的TCP分段
        3、以太网帧的payload大于MTU进行IP分片
        
    TCP粘包、拆包解决方案
        1、消息定长
        2、在包尾部增加特殊字符进行分割,例如回车
        3、将消息分为消息头和消息体,在消息头中包含表示消息总总长度的字段,然后进行业务处理
    
    Hetty解决粘包、拆包问题
        1、分隔符 DelimiterBasedFrameDecoder
            在Server类和Client类中initChannel方法中
                ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
                sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));
                //设置字符串形式的解码
                sc.pipeline().addLast(new StringDecoder());
                
                sc.pipeline().addLast(new ServerHandler());
                
            Server类
                public class Server {
                    public static void main(String[] args) throws InterruptedException {
                        //第一个线程组 是用于接收Client端连接
                        EventLoopGroup bossGroup = new NioEventLoopGroup();
                        //第二个线程组 适用于实际的业务处理操作的
                        EventLoopGroup workerGroup = new NioEventLoopGroup();
                        
                        //创建一个辅助类Bootstrap,就是对我们Server进行一系列的配置
                        ServerBootstrap b = new ServerBootstrap(); // (2)
                        //把两个工作线程组加入进来
                         b.group(bossGroup, workerGroup)
                         //我要指定使用NioserverSocketChannel这种类型的通道
                          .channel(NioServerSocketChannel.class)
                          //一定要使用childHandler去绑定具体的事件处理器
                          .childHandler(new ChannelInitializer<SocketChannel>() {
                              @Override
                            protected void initChannel(SocketChannel sc) throws Exception {
                                // TODO Auto-generated method stub
                                ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
                                sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));
                                sc.pipeline().addLast(new StringDecoder());
                                sc.pipeline().addLast(new ServerHandler());
                            }
                        });
                        
                         ChannelFuture f = b.bind(8765).sync();
                        
                         f.channel().closeFuture().sync();
                        
                         bossGroup.shutdownGracefully();
                         workerGroup.shutdownGracefully();
                    }
                }
            
            ServerHandler类
                public class ServerHandler extends ChannelHandlerAdapter{
                    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                            String request = (String)msg;
                            System.out.println("Server:"+request);
                            //写给客户端
                            String response = "我是反馈的信息$_";
                            ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes()))
                                .addListener(ChannelFutureListener.CLOSE);
                    }
                    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                        // TODO Auto-generated method stub
                        cause.printStackTrace();
                        ctx.close();
                    }
                }
            
            Client类
                public class Client {
                    public static void main(String[] args) throws Exception{
                        EventLoopGroup group = new NioEventLoopGroup();

                        Bootstrap b = new Bootstrap();
                        b.group(group)
                        .channel(NioSocketChannel.class)
                        .handler(new ChannelInitializer<SocketChannel>(){
                            @Override
                            protected void initChannel(SocketChannel sc) throws Exception {
                                // TODO Auto-generated method stub
                                ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
                                sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));
                                sc.pipeline().addLast(new StringDecoder());
                                sc.pipeline().addLast(new ClientHandler());
                            }
                        });

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

                        cf1.channel().writeAndFlush(Unpooled.wrappedBuffer("hello netty!$_".getBytes()));
                        cf1.channel().writeAndFlush(Unpooled.wrappedBuffer("hello netty!$_".getBytes()));

                        cf1.channel().closeFuture().sync();
                        group.shutdownGracefully();
                    }
                }
            
            ClientHandler类
                public class ClientHandler extends ChannelHandlerAdapter{
                    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                        try {
                            //do something msg
                            String data = (String)msg;
                            System.out.println("Client: " + data);
                            
                        } finally {
                            ReferenceCountUtil.release(msg);
                        }
                        
                    }
                    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                        // TODO Auto-generated method stub
                        cause.printStackTrace();
                        ctx.close();
                    }
                }
                
        2、FixedLengthFrameDecoder(定长)
            在Server类和Client类中initChannel方法中
                //设置定长字符串接收
                sc.pipeline().addLast(new FixedLengthFrameDecoder(5));
                //设置字符串的解码
                sc.pipeline().addLast(new StringDecoder());
                sc.pipeline().addLast(new ServerHandler());
    
Netty编解码技术
    编解码技术就是java序列化技术,目的:第一进行网络传输,第二对象持久化
    虽然我们可以使用java进行对象序列化,netty去传输,但是java序列化的硬伤太多,比如
        java序列化没法跨语言、序列化后码流太大、序列化性能太低等等
        
    主流框架:
        JBoss的Marshalling包
        goole的Protobuf
        基于Protobuf的Kyro
        MessagePack框架
        
    JBoss的Marshalling是一个java对象序列化包,对JDK默认的序列化框架进行了优化,但又保持
        跟java.io.Serializable接口的兼容,同时增加了一些可调的参数和附加特性
        
        在Server类和Client类中initChannel方法中
        sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
        sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
        sc.pipeline().addLast(new ReadTimeoutHandler(5));
        sc.pipeline().addLast(new ServerHandler());
        
        ServerHandler中
        Req req = (Req) msg;
        System.out.println("server:"+req.getId()+","+req.getName()+","+req.getRequestMessage());
        
        Resp resp = new Resp();
        resp.setId(req.getId());
        resp.setName(req.getName());
        resp.setResponseMessage(req.getRequestMessage());
        ctx.writeAndFlush(resp);
        
        MarshallingCodeCFactory类
        public final class MarshallingCodeCFactory {
            /**
             * 创建Jboss Marshalling解码器MarshallingDecoder
             * @return MarshallingDecoder
             */
            public static MarshallingDecoder buildMarshallingDecoder() {
                //首先通过Marshalling工具类的精通方法获取Marshalling实例对象 参数serial标识创建的是java序列化工厂对象。
                final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
                //创建了MarshallingConfiguration对象,配置了版本号为5
                final MarshallingConfiguration configuration = new MarshallingConfiguration();
                configuration.setVersion(5);
                //根据marshallerFactory和configuration创建provider
                UnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration);
                //构建Netty的MarshallingDecoder对象,俩个参数分别为provider和单个消息序列化后的最大长度
                MarshallingDecoder decoder = new MarshallingDecoder(provider, 1024);
                return decoder;
            }

            /**
             * 创建Jboss Marshalling编码器MarshallingEncoder
             * @return MarshallingEncoder
             */
            public static MarshallingEncoder buildMarshallingEncoder() {
                final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
                final MarshallingConfiguration configuration = new MarshallingConfiguration();
                configuration.setVersion(5);
                MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, configuration);
                //构建Netty的MarshallingEncoder对象,MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组
                MarshallingEncoder encoder = new MarshallingEncoder(provider);
                return encoder;
            }
        }
        
webSocket将网络套接字引入到了客户端和服务端,
    ws特点:
        单一的tcp连接,双方可通信
        对代理、防火墙和路由器透明
        无头部信息、Cookie和身份验证
        无安全开销
        通过ping\pong帧保持链路激活
        服务器可主动传递给客户端,不在需要客户端轮询

实践
    两台机器或者多台使用Netty进行通信
        第一种,使用长连接通道不断开的形式进行通信,服务器和客户端通道一直处于开启状态
        第二种,一次性批量提交数据,采用短连接方式
        第三种,使用特殊的长连接,在指定的时间内,没有通信就断开,下次通信在建立连接
            如何设置超时后关闭通道,关闭后又如何再次建立连接
                5秒钟关闭,server和Client都要设置
                sc.pipeline().addLast.(new ReadTimeoutHandler(5));
                关闭之后,Client开启一个线程去建立连接
                new Thread(new Runnable(){
                    public void run() {
                        try {
                            System.out.println("进入子线程");
                            ChannelFuture cf = c.getChannelFuture();//一个连接服务器方法
                            System.out.println(cf.channel().isActive());
                            System.out.println(cf.channel().isOpen());
                            //再次发送数据
                            Req request = new Req();
                            request.setId(""+4);
                            request.setName("pro"+4);
                            request.setRequestMessage("数据信息"+4);
                            cf.channel().writeAndFlush(request);
                            cf.channel().closeFuture().sync();
                            System.out.println("子线程结束");
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
                
                
            客户端宕机时关闭通道,下次客户端重启之后再次建立连接,服务器宕机重启后,如何建立连接
    
    心跳检测
    
    Netty实现文件服务器上传下载
        相比Struts或springmvc,Netty上传下载支持大文件,异步,并发,性能好,非阻塞
        
    fastdfs支持小文件上传,hdfs支持大文件、断点续传
        
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
旋转变压器---数字转换器作为现代伺服系统中被广泛使用的角位置测量系统,大量应用于高精度及大中型数控系统、机器人控制、工业控制、武器火力控制及惯性导航领域中。 传统的角测量系统面临的问题有:体积、重量、功耗偏大,调试、误差补偿试验复杂,费用较高。本文从微型化、智能化的方向进行研究,是解决传统角测量系统所面临问题的好途径。 本文所研究的旋转变压器---数字转换器是由信号调理模块、系统芯片C8051F064和输出控制模块组成的。整个系统的三路输入信号为X=AsinOcosar、Y=Acosθcos ot和Z=Ucosar(基准信号),输出信号为偏转角θ,输出形式为16 位数字量。信号调理模块是由模拟电路组成的,包括信号输入电路、相敏整流电路、滤波电路和直流稳压电源电路,其难点在于相敏整流电路的设计。信号调理模块的主要功能是把输入的交流信号X=AsinOcosor、Y=Acosθcosot转变成直流信号Bsinθ和Bcosθ,并使输出的直流信号在0~2.4V之间;系统芯片C8051F064是CYGNAL公司近年来推出的一款功能齐全的完全集成的混合信号片上系统型单片机。在本文所设计的系统中,系统芯片的输入信号为直流信号Bsinθ和Bcosθ,通过片内自带的2个16位A/D转换器对输入信号的数据进行采样和转换,并对转换完的数据进行滤波处理,以减小由于外界干扰而产生的误差,再用除法和反正切函数解算出偏转角θ的16位数字量;输出控制模块主要完成的功能是通过UARTO向计算机实时发送由单片机计算出来的偏转角度0的16位数字量,而串口的RS-232电平与单片机系统采用的是TTL电平之间的转换所采用的转换芯片是MC1488和MC1489。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值