一、Netty入门

一、概述

Netty是一个异步的,基于事件驱动的,网络应用框架;

avatar

目前大多使用netty 4,netty 5被废弃了

二、大纲

  • Netty入门

二、入门示例

1. 示例

开发一个简单的服务器,绑定端口8899,服务启动后每次访问都返回helloworld字符串

  • Server:入口
package com.learner.netty.ch1;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * @Desc:
 * @author: lizza1643@gmail.com
 * @date: 2019-11-28
 */
public class Server {

    public static void main(String[] args) throws InterruptedException {
        // boosGroup线程组负责获取连接,转接给workGroup,workGroup处理连接
        EventLoopGroup boosGroup = new NioEventLoopGroup();
        EventLoopGroup workGroup = new NioEventLoopGroup();

        try {
            // ServerBootstrap用于简化启动netty服务端
            ServerBootstrap serverBootstrap = new ServerBootstrap();

            // 将boosGroup和workGroup进行绑定,利用反射创建通道,绑定子处理器
            serverBootstrap.group(boosGroup, workGroup)
                    .channel(NioServerSocketChannel.class)  // 反射创建实例
                    .childHandler(new ServerInitializer());   // 子处理器,自己的请求处理服务器,用于处理请求

            // 绑定端口
            ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
            channelFuture.channel().closeFuture().sync();
        } finally {
            boosGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }
}
  • ServerInitializer:服务初始化
package com.learner.netty.ch1;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http2.Http2Codec;

/**
 * @Desc: 初始化管道
 * @author: lizza1643@gmail.com
 * @date: 2019-11-28
 */
public class ServerInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        // pipeline是一个管道,其中有很多的channelHandle(相当于拦截器),用于处理不同的事务
        ChannelPipeline pipeline = ch.pipeline();

        pipeline.addLast("serverCodec", new HttpServerCodec());
        pipeline.addLast("channelHandle", new ChannelHandle());
    }
}
  • ChannelHandle:自定义处理器
package com.learner.netty.ch1;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;

/**
 * @Desc: 自定义的handle,用于处理自己的业务,需要继承SimpleChannelInboundHandler
 * @author: lizza1643@gmail.com
 * @date: 2019-11-28
 */
public class ChannelHandle extends SimpleChannelInboundHandler<HttpObject> {

    /**
     * 用于获取请求,并进行处理,最后返回响应
     * @author: lizza@vizen.cn
     * @date: 2019/11/28 9:36 下午
     * @param ctx
     * @param msg
     * @return void
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {

        System.out.println("请求处理");

        if (msg instanceof HttpRequest) {
            HttpRequest request = (HttpRequest) msg;

            // 获取请求类型
            System.out.println("请求类型:"+request.method().name());

            // 获取访问地址
            System.out.println("请求地址:"+request.uri());

            // 1. 构建ByteBuf
            ByteBuf content = Unpooled.copiedBuffer("Hello, Netty 学习!", CharsetUtil.UTF_8);
            // 2. 根据ByteBuf构建Response
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
                    HttpResponseStatus.OK, content);
            // 3. 设置响应头
            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
            // 4. 返回
            ctx.writeAndFlush(response);
        }

    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        super.handlerAdded(ctx);
        System.out.println("1. handle added");
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelRegistered(ctx);
        System.out.println("2. channel registered");
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        System.out.println("3. channel active");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        System.out.println("4. channel inactive");
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        super.channelUnregistered(ctx);
        System.out.println("5. channel unregistered");
    }
}
  • 请求示例
curl 'http://localhost:8899'
  • 返回示例:
Hello, Netty 学习!

三、开发流程

上面的入门示例的开发流程总结如下:

  1. 创建两个EventLoopGroup线程组:boos,work
// boosGroup线程组负责获取连接,转接给workGroup,workGroup处理连接
EventLoopGroup boosGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();

boos负责获取连接,work负责处理连接

  1. 创建ServerBootStrap实例,用于绑定boss和work,创建channel,绑定handle,绑定端口,启动服务,最后优雅的关闭服务
// 将boosGroup和workGroup进行绑定,利用反射创建通道,绑定子处理器
serverBootstrap.group(boosGroup, workGroup)
        .channel(NioServerSocketChannel.class)  // 反射创建实例
        .childHandler(new ServerInitializer());   // 子处理器,自己的请求处理服务器,用于处理请求
// 绑定端口
ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
channelFuture.channel().closeFuture().sync();
boosGroup.shutdownGracefully();
workGroup.shutdownGracefully();

3.继承ChannelInitializer创建Initializer,重写initChannel

@Override
protected void initChannel(SocketChannel ch) throws Exception {
    // pipeline是一个管道,其中有很多的channelHandle(相当于拦截器),用于处理不同的事务
    ChannelPipeline pipeline = ch.pipeline();

    pipeline.addLast("serverCodec", new HttpServerCodec());
    pipeline.addLast("channelHandle", new ChannelHandle());
}

ChannelPipeline是一个管道,里边可以添加很多的handle,每个handle可以处理不同的事务

  1. 继承SimpleChannelInboundHandler,创建自己的ChannelHandle,重写channelRead0()用于处理自己的业务
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {

    System.out.println("请求处理");

    if (msg instanceof HttpRequest) {
        HttpRequest request = (HttpRequest) msg;

        // 获取请求类型
        System.out.println("请求类型:"+request.method().name());

        // 获取访问地址
        System.out.println("请求地址:"+request.uri());

        // 1. 构建ByteBuf
        ByteBuf content = Unpooled.copiedBuffer("Hello, Netty 学习!", CharsetUtil.UTF_8);
        // 2. 根据ByteBuf构建Response
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
                HttpResponseStatus.OK, content);
        // 3. 设置响应头
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
        response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
        // 4. 返回
        ctx.writeAndFlush(response);
    }

}

四、Netty执行流程

1. 总览

在自定义的handle中可以重写handlerAdded,channelRegistered,channelActive,channelInactive,channelUnregistered这五个方法,并进行打印,用来分析Netty的执行流程

package com.learner.netty.ch1;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;

/**
 * @Desc: 自定义的handle,用于处理自己的业务,需要继承SimpleChannelInboundHandler
 * @author: lizza1643@gmail.com
 * @date: 2019-11-28
 */
public class ChannelHandle extends SimpleChannelInboundHandler<HttpObject> {

    /**
     * 用于获取请求,并进行处理,最后返回响应
     * @author: lizza@vizen.cn
     * @date: 2019/11/28 9:36 下午
     * @param ctx
     * @param msg
     * @return void
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {

        System.out.println("请求处理");

        if (msg instanceof HttpRequest) {
            HttpRequest request = (HttpRequest) msg;

            // 获取请求类型
            System.out.println("请求类型:"+request.method().name());

            // 获取访问地址
            System.out.println("请求地址:"+request.uri());

            // 1. 构建ByteBuf
            ByteBuf content = Unpooled.copiedBuffer("Hello, Netty 学习!", CharsetUtil.UTF_8);
            // 2. 根据ByteBuf构建Response
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
                    HttpResponseStatus.OK, content);
            // 3. 设置响应头
            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
            // 4. 返回
            ctx.writeAndFlush(response);
        }

    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        super.handlerAdded(ctx);
        System.out.println("1. handle added");
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelRegistered(ctx);
        System.out.println("2. channel registered");
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        System.out.println("3. channel active");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        System.out.println("4. channel inactive");
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        super.channelUnregistered(ctx);
        System.out.println("5. channel unregistered");
    }
}

启动服务,查看执行结果:

> Task :Server.main()
1. handle added
2. channel registered
3. channel active
请求处理
请求类型:GET
请求地址:/
请求处理
4. channel inactive
5. channel unregistered

可以看到其执行流程是:

  1. handle added
  2. channel registered
  3. channel active
  4. 处理业务逻辑
  5. channel inactive
  6. channel unregistered
内容概要:本文详细介绍了基于FPGA的144输出通道可切换电压源系统的设计与实现,涵盖系统总体架构、FPGA硬件设计、上位机软件设计以及系统集成方案。系统由上位机控制软件(PC端)、FPGA控制核心和高压输出模块(144通道)三部分组成。FPGA硬件设计部分详细描述了Verilog代码实现,包括PWM生成模块、UART通信模块和温度监控模块。硬件设计说明中提及了FPGA选型、PWM生成方式、通信接口、高压输出模块和保护电路的设计要点。上位机软件采用Python编写,实现了设备连接、命令发送、序列控制等功能,并提供了个图形用户界面(GUI)用于方便的操作和配置。 适合人群:具备定硬件设计和编程基础的电子工程师、FPGA开发者及科研人员。 使用场景及目标:①适用于需要精确控制多通道电压输出的实验环境或工业应用场景;②帮助用户理解和掌握FPGA在复杂控制系统中的应用,包括PWM控制、UART通信及多通道信号处理;③为研究人员提供个可扩展的平台,用于测试和验证不同的电压源控制算法和策略。 阅读建议:由于涉及硬件和软件两方面的内容,建议读者先熟悉FPGA基础知识和Verilog语言,同时具备定的Python编程经验。在阅读过程中,应结合硬件电路图和代码注释,逐步理解系统的各个组成部分及其相互关系。此外,实际动手搭建和调试该系统将有助于加深对整个设计的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值