Netty 框架学习(二):DelimiterBasedFrameDecoder和FixedLengthFrameDecoder

TCP以流的方式进行数据传输,上层应用协议为了对消息进行区分,一般采用如下4种方式:

1.消息长度固定,累计读取到消息长度总和为定长Len的报文之后即认为是读取到了一个完整的消息。计数器归位,重新读取。
2. 将回车换行符作为消息结束符。
3. 将特殊的分隔符作为消息分隔符,回车换行符是他的一种。
4. 通过在消息头定义长度字段来标识消息总长度。

LineBasedframeDecoder属于第二种,今天我们要说的DelimiterBasedFrameDecoder和FixedLengthFrameDecoder属于第三种和第一种。DelimiterBasedFrameDecoder用来解决以特殊符号作为消息结束符的粘包问题,FixedLengthFrameDecoder用来解决定长消息的粘包问题。

一、DelimiterBasedFrameDecoder

服务端

1、EchoServer
/**
 * @author shuliangzhao
 * @Title: EchoServer
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/8/21 20:53
 */
public class EchoServer {

    public void start(int port) {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workGroup = new NioEventLoopGroup();
        ServerBootstrap serverBootstrap = new ServerBootstrap()
                .group(bossGroup,workGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new EchoServerChannelHandler());
        try {
            ChannelFuture future = serverBootstrap.bind(port).sync();
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        new EchoServer().start(8080);
    }
}
2、EchoServerChannelHandler
/**
 * @author shuliangzhao
 * @Title: EchoServerChannelHandler
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/8/21 20:59
 */
public class EchoServerChannelHandler extends ChannelInitializer<SocketChannel> {

    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();
        ByteBuf byteBuf = Unpooled.copiedBuffer("\t".getBytes());
        pipeline.addLast(new DelimiterBasedFrameDecoder(1024,byteBuf));
        pipeline.addLast(new StringDecoder());
        pipeline.addLast(new StringEncoder());
        pipeline.addLast(new EchoServerHandler());
    }
}
3、EchoServerHandler
public class EchoServerHandler extends ChannelInboundHandlerAdapter {

    private int counter;

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String body = (String) msg;
        System.out.println("server reciver oder:" + body + ";this counter is:" + ++counter);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
    }
}

客户端

1、EchoClient
public class EchoClient {

    public void start(String address,int port) {
        EventLoopGroup group = new NioEventLoopGroup();

        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(new EchoClientChannelHandler());

        try {
            ChannelFuture future = bootstrap.connect(address,port).sync();
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            group.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        new EchoClient().start("127.0.0.1",8080);
    }
}
2、EchoClientChannelHandler
public class EchoClientChannelHandler extends ChannelInitializer<SocketChannel> {
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();
        /*
         * 这个地方的 必须和服务端对应上。否则无法正常解码和编码
         */
        ByteBuf delimiter = Unpooled.copiedBuffer("\t".getBytes());
        pipeline.addLast(new DelimiterBasedFrameDecoder(1024,delimiter));
        pipeline.addLast( new StringDecoder());
        pipeline.addLast( new StringEncoder());

        // 客户端的逻辑
        pipeline.addLast( new EchoClientHandler());
    }
}

3、EchoClientHandler
public class EchoClientHandler extends ChannelInboundHandlerAdapter {

    private byte[] req;

    private int counter;

    public EchoClientHandler() {
        req = ("There are moments in life when you miss\t" +
        "someone so much that you just want to pick\t"    +
        "them from your dreams and hug them for real!\t"    +
        "Dream what you want to dream;go where you want\t"    +
        "to go be what you want to be,because you have only\t"   +
        "one life and one chance to do all the things you want to do\t").getBytes();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ByteBuf message = Unpooled.buffer(req.length);
        message.writeBytes(req);
        ctx.writeAndFlush(message);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String body = (String) msg;
        System.out.println("client reciver is :" + body + "this is counter:" + ++counter);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}

运行结果:
在这里插入图片描述
这里我们添加DelimiterBasedFrameDecoder解码器并且手动指定消息分隔符为:”\t”。我们可以看一下DelimiterBasedFrameDecoder的构造方法:

public DelimiterBasedFrameDecoder(int maxFrameLength, boolean stripDelimiter, ByteBuf delimiter) {
        this(maxFrameLength, stripDelimiter, true, delimiter);
}

maxFrameLength:解码的帧的最大长度

stripDelimiter:解码时是否去掉分隔符

failFast:为true,当frame长度超过maxFrameLength时立即报TooLongFrameException异常,为false,读取完整个帧再报异常

delimiter:分隔符

二、FixedLengthFrameDecoder

FixedLengthFrameDecoder是固定长度解码器,它能够按照指定的长度对消息进行自动解码。
用法如下:
pipeline.addLast(new FixedLengthFrameDecoder(23));//参数为一次接受的数据长度。

<think>好的,我现在需要回答用户关于Windows任务计划程序返回代码2147942402的问题。首先,我需要理解这个错误代码的具体含义。用户提供的引用中提到了错误值2147942402,而引用[4]提到返回代码为2,并指出最小支持的服务器是Windows Server 2008。可能这两个代码之间有关联。 我记得Windows系统通常使用十六进制错误代码,但任务计划程序返回的有时是十进制数字。所以需要将十进制的2147942402转换为十六进制。用计算器转换的话,2147942402转换成十六进制是0x80070002。这个代码看起来像是系统错误代码。接下来,我需要确认0x80070002代表什么错误。 查阅资料,系统错误代码0x80070002通常对应的是“系统找不到指定的文件”。也就是说,当任务计划程序尝试执行某个任务时,无法找到指定的脚本或可执行文件路径。这可能是因为路径错误、文件被移动或删除,或者权限问题导致无法访问文件。 用户的引用[1]提到任务路径是“\Microsoft\get_cpu_usage_log”,可能存在路径格式问题。正确的路径应该包含完整的绝对路径,并且需要确保任务计划程序有权限访问该路径。引用[3]也提到执行bat脚本返回0x1,通常与路径或脚本内部错误有关,所以类似的问题可能适用。 总结起来,错误代码2147942402(0x80070002)表示文件未找到。用户需要检查任务配置中的操作路径是否正确,确保文件存在,并且任务计划程序有足够的权限访问该文件。同时,引用[2]提到的确保Task Scheduler服务已启动也很重要,如果服务未运行,任务自然无法执行。 接下来,生成相关问题时需要考虑用户可能的后续疑问,比如如何转换错误代码、如何检查文件路径、权限设置方法等。确保问题覆盖错误处理的不同方面,帮助用户全面排查问题。</think>任务计划程序返回代码$2147942402$的十六进制表示为$0x80070002$,对应系统错误代码**ERROR_FILE_NOT_FOUND**,表示系统找不到指定的文件或路径[^4]。 ### 具体原因分析: 1. **脚本/程序路径错误** 任务配置中"操作"选项卡的路径未指向真实存在的文件,例如: - 路径包含多余空格或拼写错误 - 使用了相对路径而非绝对路径 - 文件被移动或删除 2. **权限问题** 即使路径正确,若任务计划程序未获得以下权限仍会报错: - 未勾选"不管用户是否登录都要运行" - 未选择"使用最高权限运行" - 用户账户无目标文件的读取权限 3. **依赖环境缺失** 执行Python脚本时可能缺少: - Python解释器未加入系统PATH - 脚本依赖第三方库未安装 - 未指定完整解释器路径如`C:\Python39\python.exe` ### 解决方法: ```bat :: 正确路径示例(bat文件) @echo off "C:\Python39\python.exe" "D:\scripts\get_cpu_usage_log.py" ``` 1. 检查任务属性的"常规"选项卡: - 勾选"使用最高权限运行" - 选择配置为当前系统版本(如Windows Server 2008 R2)[^2] 2. 验证服务状态: ```powershell Get-Service Schedule | Start-Service # 启动Task Scheduler服务 ``` 3. 手动测试执行: ```cmd schtasks /run /tn "\Microsoft\get_cpu_usage_log" # 触发任务立即执行 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

境里婆娑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值