Netty(7)-构建pipeline、channelHandler、Decoder和Encoder

【Netty】模型篇三:Netty核心组件讲解 本文针对上一篇文章 【Netty】模型篇二:通过案例分析Netty线程模型以及Netty的核心组件 中涉及到的Netty核心组件进行分析讲解。 注意:这里强烈建议大家先学习一下 Java NIO,再来看本文。 阅读详情

一.pipeline和channelHandler

使用pipeline,把复杂的逻辑从单独的一个 channelHandler 中抽取出来,pipeline构造成一个双向链表将一个个channelHandler串联起来,形成逻辑处理责任链,每个hanlder只负责处理各自的协议包:

在这里插入图片描述

1.channelHandler的分类

在这里插入图片描述
ChannelHandler 有两大子接口:

1.ChannelInboundHandler

ChannelInboundHandler用以处理读数据的逻辑,比如,我们在一端读到一段数据,首先要解析这段数据,然后对这些数据做一系列逻辑处理,最终把响应写到对端, 在开始组装响应之前的所有的逻辑,都可以放置在 ChannelInboundHandler 里处理,它的一个最重要的方法就是 channelRead()。

2.ChannelOutBoundHandler

ChannelOutBoundHandler处理写数据的逻辑,它是定义我们一端在组装完响应之后,把数据写到对端的逻辑,比如,我们封装好一个 response 对象,接下来我们有可能对这个 response 做一些其他的特殊逻辑,然后,再编码成 ByteBuf,最终写到对端,它里面最核心的一个方法就是 write()。

这两个子接口分别有对应的默认实现,ChannelInboundHandlerAdapter,和 ChanneloutBoundHandlerAdapter,它们分别实现了两大接口的所有功能,默认情况下会把读写事件传播到下一个 handler。

2.channelHandler的事件传播

在服务端的 pipeline 添加三个 ChannelInboundHandler

  • NettyServer
serverBootstrap
        .childHandler(new ChannelInitializer<NioSocketChannel>() {
            protected void initChannel(NioSocketChannel ch) {
                // inBound,处理读数据的逻辑链
                ch.pipeline().addLast(new InBoundHandlerA());
                ch.pipeline().addLast(new InBoundHandlerB());
                ch.pipeline().addLast(new InBoundHandlerC());
                
                // outBound,处理写数据的逻辑链
                ch.pipeline().addLast(new OutBoundHandlerA());
                ch.pipeline().addLast(new OutBoundHandlerB());
                ch.pipeline().addLast(new OutBoundHandlerC());
            }
        });
  • InBoundHandler
public class InBoundHandlerA extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("InBoundHandlerA: " + msg);
        super.channelRead(ctx, msg);
    }
}

public class InBoundHandlerB extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("InBoundHandlerB: " + msg);
        super.channelRead(ctx, msg);
    }
}

public class InBoundHandlerC extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("InBoundHandlerC: " + msg);
        super.channelRead(ctx, msg);
    }
}
  • OutBounddHandler
public class OutBoundHandlerA extends ChannelOutboundHandlerAdapter {
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        System.out.println("OutBoundHandlerA: " + msg);
        super.write(ctx, msg, promise);
    }
}

public class OutBoundHandlerB extends ChannelOutboundHandlerAdapter {
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        System.out.println("OutBoundHandlerB: " + msg);
        super.write(ctx, msg, promise);
    }
}

public class OutBoundHandlerC extends ChannelOutboundHandlerAdapter {
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        System.out.println("OutBoundHandlerC: " + msg);
        super.write(ctx, msg, promise);
    }
}

执行程序

在这里插入图片描述

可以看到,inBoundHandler的执行顺序与我们添加的顺序相同,而outBoundHandler的执行顺序与我们添加的顺序相反。

3.pipeline的结构与channelHandler的执行顺序
  1. pipeline结构
    在这里插入图片描述
  2. channelHandler执行顺序
    在这里插入图片描述

二.构建客户端和服务端的pipeline与Decoder和Encoder

Netty 内置了很多开箱即用的 ChannelHandler。下面,我们通过学习 Netty 内置的 ChannelHandler 来逐步构建我们的 pipeline。

1.ChannelInboundHandlerAdapter 与 ChannelOutboundHandlerAdapter

首先是 ChannelInboundHandlerAdapter ,这个适配器主要用于实现其接口 ChannelInboundHandler 的所有方法,这样我们在编写自己的 handler 的时候就不需要实现 handler 里面的每一种方法,而只需要实现我们所关心的方法,默认情况下,对于 ChannelInboundHandlerAdapter,我们比较关心的是他的如下方法

  • ChannelInboundHandlerAdapter
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    ctx.fireChannelRead(msg);
}

他的作用就是接收上一个 handler 的输出,这里的 msg 就是上一个 handler 的输出。大家也可以看到,默认情况下 adapter 会通过 fireChannelRead() 方法直接把上一个 handler 的输出结果传递到下一个 handler。(责任链模式)

与 ChannelInboundHandlerAdapter 类似的类是 ChannelOutboundHandlerAdapter,它的核心方法如下

  • ChannelOutboundHandlerAdapter
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    ctx.write(msg, promise);
}

默认情况下,这个 adapter 也会把对象传递到下一个 outBound 节点,它的传播顺序与 inboundHandler 相反,这里就不再对这个类展开了。

2.Decoder与Encoder
1.PacketDecoder

通常情况下,无论我们是在客户端还是服务端,当我们收到数据之后,首先要做的事情就是把二进制数据转换到我们的一个 Java 对象,所以 Netty 很贴心地写了一个父类,来专门做这个事情,下面我们来看一下,如何使用这个类来实现服务端的解码

public class PacketDecoder extends ByteToMessageDecoder {

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) {
        out.add(PacketCodeC.INSTANCE.decode(in));
    }
}

当我们继承了 ByteToMessageDecoder 这个类之后,我们只需要实现一下 decode() 方法,这里的 in 大家可以看到,传递进来的时候就已经是 ByteBuf 类型,所以我们不再需要强转,第三个参数是 List 类型,我们通过往这个 List 里面添加解码后的结果对象,就可以自动实现结果往下一个 handler 进行传递,这样,我们就实现了解码的逻辑 handler。

另外,值得注意的一点,对于 Netty 里面的 ByteBuf,我们使用 4.1.6.Final 版本,默认情况下用的是堆外内存,在 ByteBuf 这一小节中我们提到,堆外内存我们需要自行释放,在我们前面小节的解码的例子中,其实我们已经漏掉了这个操作,这一点是非常致命的,随着程序运行越来越久,内存泄露的问题就慢慢暴露出来了, 而这里我们使用 ByteToMessageDecoder,Netty 会自动进行内存的释放

当我们通过解码器把二进制数据转换到 Java 对象即指令数据包之后,就可以针对每一种指令数据包编写逻辑了。

2.PacketEncoder

处理完请求之后,我们都会给客户端一个响应,在写响应之前,我们需要把响应对象编码成 ByteBuf。

  • LoginRequestHandler
public class LoginRequestHandler extends SimpleChannelInboundHandler<LoginRequestPacket> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, LoginRequestPacket loginRequestPacket) {
        LoginResponsePacket loginResponsePacket = login(loginRequestPacket);
        ByteBuf responseByteBuf = PacketCodeC.INSTANCE.encode(ctx.alloc(), loginResponsePacket);
        ctx.channel().writeAndFlush(responseByteBuf);
    }
}
  • MessageRequestHandler
public class MessageRequestHandler extends SimpleChannelInboundHandler<MessageRequestPacket> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, MessageRequestPacket messageRequestPacket) {
        MessageResponsePacket messageResponsePacket = receiveMessage(messageRequestPacket);
        ByteBuf responseByteBuf = PacketCodeC.INSTANCE.encode(ctx.alloc(), messageRequestPacket);
        ctx.channel().writeAndFlush(responseByteBuf);
    }
}

我们注意到,我们处理每一种指令完成之后的逻辑是类似的,都需要进行编码,然后调用 writeAndFlush() 将数据写到客户端,这个编码的过程其实也是重复的逻辑,而且在编码的过程中,我们还需要手动去创建一个 ByteBuf,如下过程

  • PacketUtil.java
public ByteBuf encode(ByteBufAllocator byteBufAllocator, Packet packet) {
    // 1. 创建 ByteBuf 对象
    ByteBuf byteBuf = byteBufAllocator.ioBuffer();
    // 2. 序列化 java 对象

    // 3. 实际编码过程

    return byteBuf;
}

而Netty 提供了一个特殊的 channelHandler 来专门处理编码逻辑,我们不需要每一次将响应写到对端的时候调用一次编码逻辑进行编码,也不需要自行创建 ByteBuf,这个类叫做 MessageToByteEncoder,从字面意思也可以看出,它的功能就是将对象转换到二进制数据。

  • PacketEncoder
public class PacketEncoder extends MessageToByteEncoder<Packet> {

    @Override
    protected void encode(ChannelHandlerContext ctx, Packet packet, ByteBuf out) {
        PacketUtil.INSTANCE.encode(out, packet);
    }
}
  • PackageUtil
/**
 * @Auther: ARong
 * @Date: 2020/2/4 9:14 下午
 * @Description: 用于包编码和解码
 */
public class PacketUtil {

    // 饿汉单例模式
    public static PacketUtil INSTANCE = new PacketUtil();

    private PacketUtil(){}
    /*
     * @Author ARong
     * @Description 将packet编码为byteBuf
     * @Date 2020/2/9 9:04 下午
     * @Param [byteBuf, packet]
     * @return void
     **/
    public void encode(ByteBuf byteBuf, Packet packet) {
        // 获取序列化器序列化对象
        MySerializer serializer = SerializerFactory.getSerializer(packet.getSerMethod());
        byte[] data = serializer.serialize(packet);
        // 按照通信协议填充ByteBUf
        byteBuf.writeInt(packet.getMagic());// 魔数
        byteBuf.writeByte(packet.getVersion()); // 版本号
        byteBuf.writeByte(packet.getSerMethod()); // 序列化方式
        byteBuf.writeByte(packet.getCommand()); // 指令
        byteBuf.writeInt(data.length);// 数据长度
        byteBuf.writeBytes(data); // 数据
    }

    /*
     * @Author ARong
     * @Description 将ByteBuf按照约定序列化方式解码成Packet
     * @Date 2020/2/4 9:21 下午
     * @Param [byteBuf]
     * @return io_learn.netty.part4_protocol.packet.Packet
     **/
    public Packet decode(ByteBuf byteBuf) {
        // 暂不判断魔数,跳过
        byteBuf.skipBytes(4);
        // 暂不判断魔数版本号,跳过
        byteBuf.skipBytes(1);
        // 获取序列化方式
        byte serMethod = byteBuf.readByte();
        // 获取指令
        byte command = byteBuf.readByte();
        // 获取数据包长度
        int length = byteBuf.readInt();
        // 获取存储数据的字节数组
        byte[] data = new byte[length];
        byteBuf.readBytes(data);
        // 反序列化数据,获取Packet
        Class<? extends Packet> packetType = getPacketType(command);
        Packet res = SerializerFactory.getSerializer(serMethod).deserialize(packetType, data);
        return res;
    }


    /*
     * @Author ARong
     * @Description 通过指令获取相应的Packet
     * @Date 2020/2/4 9:31 下午
     * @Param [commond]
     * @return io_learn.netty.part4_protocol.packet.Packet
     **/
    public static Class<? extends Packet> getPacketType(byte commond) {
        if (commond == Command.LOGIN_REQUEST) {
            return LoginRequestPacket.class;
        }
        if (commond == Command.LOGIN_RESPONSE) {
            return LoginResponsePacket.class;
        }
        if (commond == Command.MESSAGE_REQUEST) {
            return MessageRequestPacket.class;
        }
        if (commond == Command.MESSAGE_RESPONSE) {
            return MessageResponsePacket.class;
        }
        return null;
    }
}

之后就可以这样使用,而无需再次编码了:

public class LoginRequestHandler extends SimpleChannelInboundHandler<LoginRequestPacket> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, LoginRequestPacket loginRequestPacket) {
        ctx.channel().writeAndFlush(login(loginRequestPacket));
    }
}
3.SimpleChannelInboundHandler

回顾一下我们前面处理 Java 对象的逻辑

if (packet instanceof LoginRequestPacket) {
    // ...
} else if (packet instanceof MessageRequestPacket) {
    // ...
} else if ...

我们通过 if else 逻辑进行逻辑的处理,当我们要处理的指令越来越多的时候,代码会显得越来越臃肿,我们可以通过给 pipeline 添加多个 handler(ChannelInboundHandlerAdapter的子类) 来解决过多的 if else 问题,如下

  • XXXHandler.java
if (packet instanceof XXXPacket) {
    // ...处理
} else {
    // 责任链模式
   ctx.fireChannelRead(packet); 
}

这样一个好处就是,每次添加一个指令处理器,逻辑处理的框架都是一致的,

但是,大家应该也注意到了,这里我们编写指令处理 handler 的时候,依然编写了一段我们其实可以不用关心的 if else 判断,然后还要手动传递无法处理的对象 (XXXPacket) 至下一个指令处理器,这也是一段重复度极高的代码,因此,Netty 基于这种考虑抽象出了一个 SimpleChannelInboundHandler 对象,类型判断和对象传递的活都自动帮我们实现了,而我们可以专注于处理我们所关心的指令即可。

下面,我们来看一下如何使用 SimpleChannelInboundHandler 来简化我们的指令处理逻辑

  • LoginRequestHandler
public class LoginRequestHandler extends SimpleChannelInboundHandler<LoginRequestPacket> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, LoginRequestPacket loginRequestPacket) {
        // 登录逻辑
    }
}

SimpleChannelInboundHandler 从字面意思也可以看到,使用它非常简单,我们在继承这个类的时候,给他传递一个泛型参数,然后在 channelRead0() 方法里面,我们不用再通过 if 逻辑来判断当前对象是否是本 handler 可以处理的对象,也不用强转,不用往下传递本 handler 处理不了的对象,这一切都已经交给父类 SimpleChannelInboundHandler 来实现了,我们只需要专注于我们要处理的业务逻辑即可。

是用来处理登录的逻辑,同理,我们可以很轻松地编写一个消息处理逻辑处理器

  • MessageRequestHandler
public class MessageRequestHandler extends SimpleChannelInboundHandler<MessageRequestPacket> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, MessageRequestPacket messageRequestPacket) {

    }
}

对应我们的代码

  • NettyServer
serverBootstrap
               .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    protected void initChannel(NioSocketChannel ch) {
                        ch.pipeline().addLast(new PacketDecoder());
                        ch.pipeline().addLast(new LoginRequestHandler());
                        ch.pipeline().addLast(new MessageRequestHandler());
                        ch.pipeline().addLast(new PacketEncoder());
                    }
            });

客户端

  • NettyClient
bootstrap
        .handler(new ChannelInitializer<SocketChannel>() {
            @Override
            public void initChannel(SocketChannel ch) {
                ch.pipeline().addLast(new PacketDecoder());
                ch.pipeline().addLast(new LoginResponseHandler());
                ch.pipeline().addLast(new MessageResponseHandler());
                ch.pipeline().addLast(new PacketEncoder());
            }
        });
Spring Boot整合Netty构建高性能TCP服务:从粘包问题到生产级架构 在网络编程中,TCP协议作为面向字节流的传输层协议,其本身不维护应用层消息边界,这导致了经典的粘包与拆包问题。为解决这一问题,需要设计合理的应用层协议,其中基于长度字段的帧解码是工业级二进制协议的通用解决方案。Netty作为高性能异步事件驱动框架,其内置的LengthFieldBasedFrameDecoder等解码器组件,结合Reactor线程模型和Pipeline处理器链,为高效处理网络I/O和协议解析提供了强大支撑。这种技术组合的价值在于,它能以可控的复杂度构建高并发、低延迟的实时通信服务,广泛应用于 阅读详情

相关推荐

Spring Boot整合Netty构建TCP服务端:从粘包处理到高性能架构实战

在网络编程中,TCP协议因其可靠的数据传输特性而被广泛应用,但它不维护消息边界,这导致了经典的“粘包/拆包”问题。为了解决这一问题,开发者需要理解TCP的流式传输原理,并采用合适的应用层协议设计。Netty作为高性能的异步事件驱动网络框架,通过其内置的LengthFieldBasedFrameDecoder等解码器,能够高效、优雅地处理消息边界,确保数据包的完整解析。这种技术方案在构建高并发、低延迟的网络服务中具有重要价值,尤其适用于物联网设备接入、游戏服务器、即时通讯等场景。本文以Spring Boot与

weixin_30781775的博客 415

Netty:ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter

Netty:ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter   前面说到,服务端和客户端通讯,我们通常要绑定一个handler(Netty:Bootstrap的handler和childHandler)进行通道的监听,当收到数据时就会触发某个事件,从而进行进一步的处理。 目前我们用的比较多的就是ChannelInbound...

TuxedoLinux的博客 8764

Netty面试核心:从网络编程原理到高并发实战调优

网络编程是构建高并发分布式系统的基石,其核心在于解决传统阻塞IO模型在应对海量连接时的性能瓶颈。通过多路复用技术,一个线程可以高效管理多个网络连接,大幅减少线程资源消耗。在此基础上,Reactor线程模型进一步将连接建立与数据处理解耦,形成了高性能网络框架的骨架。Netty作为Java领域最主流的NIO框架,其价值在于将复杂的底层网络通信抽象为Channel、EventLoop、Pipeline等核心组件,并通过零拷贝、内存池等机制优化数据传输效率。在实际应用中,Netty不仅解决了粘包拆包、内存泄漏等工程

weixin_33795093的博客 455

Netty技术全解析:ChannelOutboundHandlerAdapter:简化出站事件处理的适配器

ChannelOutboundHandlerAdapter是Netty框架中处理出站事件的重要适配器类。它提供了ChannelOutboundHandler接口中所有方法的默认实现,使得用户只需要重写感兴趣的方法来处理特定的出站事件。通过使用ChannelOutboundHandlerAdapter,用户可以更加高效地开发网络应用程序,并灵活地处理各种出站事件

码到三十五 1409

Java后端面试:Netty核心原理、高并发实战与性能调优指南

网络编程是构建高性能分布式系统的基石,其核心在于高效处理海量连接与数据交换。Reactor模式作为事件驱动的经典架构,通过多路复用机制实现单线程管理多个连接,大幅提升系统吞吐量。在此基础上,Netty框架将Reactor模型与内存池化、零拷贝等优化技术结合,形成了完整的高性能网络编程解决方案。这种技术组合特别适用于需要处理高并发、低延迟场景的RPC框架、消息中间件和物联网网关。本文聚焦Java后端面试中的Netty技术栈,深入解析其线程模型、ByteBuf内存管理和粘包拆包处理机制,帮助开发者掌握高并发网络

weixin_30732487的博客 363

netty案例,netty4.1基础入门篇十《关于ChannelOutboundHandlerAdapter简单使用》

前言介绍 ChannelOutboundHandlerAdapter与ChannelInboundHandlerAdapter都是继承于ChannelHandler,并实现自己的ChannelXxxHandler。用于在消息管道中不同时机下处理处理消息。 ChannelInboundHandler拦截和处理入站事件,ChannelOutboundHandler拦截和处理出站事件。ChannelH...

bugstack虫洞栈 4844

Netty 的核心组件

Netty 的核心组件有哪些? 1. Bootstrap 与 ServerBootstrap Bootstrap 与 ServerBootstrap 是 Netty 程序的引导类,主要用于配置各种参数,并启动整个 Netty 服务。它们俩都继承自 AbstractBootstrap 抽象类,不同的是, Bootstrap 用于客户端引导,而 ServerBootstrap 用于服务端引导。 相对于 Bootstrap , ServerBootstrap 多了一个维度,用于处理 Accept

炫的博客 3万+

第三章 Netty 网络编程深度解析:从 HTTP 协议处理到自定义协议设计实战

本文系统介绍了基于Netty构建高性能HTTP服务器的完整技术体系。首先分析了Netty的核心架构,包括Reactor线程模型和ChannelPipeline工作机制;然后详细解析HTTP协议基础与Netty实现方式,展示编解码器配置;重点探讨了自定义HTTP协议的设计与实现方法,包括二进制协议头设计;最后涵盖高级特性(连接池、零拷贝等)、API网关实战、测试调试技巧等内容。全文从理论到实践,循序渐进地讲解如何利用Netty开发高性能网络应用,适合中高级开发者学习网络编程和协议设计。

ywl470812087的博客 224

netty 知识点 简要介绍

netty是一款高性能的网络应用框架,相比较原生的socket编程,它的api更加简单、易用,它对原生的tcp connection进行了包装,提供了channel、channelhandler、编解码器等概念。

wangjun5159的专栏 670

django drf 框架知识点(一)——serializer序列化器_用法全解

【django drf】序列化器:别名设置,全部参数序列化,自定义字段,只读只写,部分更新

qq_59344127的博客 1339

把STM32MP135当单片机玩:实战SD卡脱机运行LED程序(基于MP135DK开发板)

本文详细介绍了如何在STM32MP135开发板上实现SD卡脱机运行LED程序,通过裸机开发方式(Bare Metal)利用HAL库完成GPIO控制,并解析了SD卡启动流程。内容涵盖工程创建、代码编写、SD卡烧录及常见问题排查,为开发者提供了一种高性能单片机开发方案。

weixin_33734785的博客 242

Netty编程

Netty 概述 Netty是由JBOSS 提供的一个Java 开源框架。Netty提供异步的、基于事件驱动的网络应用程序框架,用以快速开发高性能、高可靠性的网络 IO 程序。 模型和异步 比较类似于上面的线程池模型,Netty抽象出两组线程池,BossGroup专门负责接收客户端连接,WorkerGroup 专门负责网络读写操作。NioEventLoop 表示一个不断循环执行处理任务的线程,每...

weixin_43794897的博客 360

ADS 使用教程(十八)Encrypting Designs using RFIP Encoder in ADS

在这一节,我们使用RFIP Encoder进行设计加密,这是一种保护知识产权和敏感设计数据的重要方法。RFIP Encoder提供了一种安全的方式来加密设计文件,确保只有授权人员能够访问和使用这些文件。

Dirge19的博客 1172

Netty4.0学习笔记系列之四:混合使用coder和handler

Handler如何使用在前面的例子中已经有了示范,那么同样是扩展自ChannelHandler的Encoder和Decoder,与Handler混合后又是如何使用的?本文将通过一个实际的小例子来展示它们的用法。 该例子模拟一个Server和Client,两者之间通过http协议进行通讯,在Server内部通过一个自定义的StringDecoder把httprequest转换成Strin...

afeyfre41671的博客 125

Python金融数据获取工具库之baostock使用详解

在金融数据分析和量化交易中,获取准确及时的市场数据是非常重要的。baostock是一个专门为中国股市数据提供支持的 Python 库,它提供了免费的股票数据接口,用户可以方便地获取股票、指数、基金等各种金融数据。本文将详细介绍baostock库,包括其安装方法、主要特性、基本和高级功能,以及实际应用场景,帮助全面了解并掌握该库的使用。

Rocky006的博客 5348

Java判断地图坐标(经度,纬度)是否在多边形区域或圆形区域内

​欢迎光临我的博客查看最新文章:在地图上,可以使用经纬度确定一个位置,如上海体育场(121.449391,31.188228),如果知道了2个地点的经纬度,我们就能在地图上找到其位置及2点的距离,百度地图或高德地图提供了相应的服务;如果将多个坐标点连成多边形区域,如何判断某个坐标点是否在多边形区域内,如下工具类。

river106的博客 3945

Netty4 ChannelPipeLine分析

Netty4 ChannelPipeLine分析  ChannelPipeLine查找ChannelHandler的顺序: DefaultChannelHandlerContext.findContextInbound()方法表示正向查找 ChannelStateHandler的实例:     Netty 4 的 ChannelHandler(s)是以链表的形式连接在一起的,

irelandken的专栏 9150

C#连接数据库报Authentication to host ‘127.0.0.1‘ for user ‘root‘ using method ‘caching_sha2_password‘ fail

所以导致的,除了上边的办法,还可以把这个加密规则修改一下,这个的修改方式有很多,具体原因是因为MySQL8.0以前的加密规则是。

weixin_42209881的博客 4131

Netty入门指南:高性能网络框架核心原理与实践

网络编程中的NIO(非阻塞I/O)技术通过事件驱动机制显著提升系统吞吐量,是构建高并发服务的核心技术。作为NIO框架的集大成者,Netty通过Reactor线程模型和零拷贝技术实现高性能网络通信,其设计的ChannelPipeline处理链和ByteBuf内存管理机制成为解决C10K问题的利器。在分布式系统架构中,Netty作为底层通信框架被Dubbo、RocketMQ等主流中间件广泛采用,特别适合需要处理大量持久连接的游戏服务器、即时通讯等场景。掌握Netty的线程模型配置和内存泄漏防护技巧,能够有效提升

weixin_30315435的博客 445

电力自动化通信协议:104/101与61850标准解析

电力系统通信协议是智能电网和变电站自动化的核心技术基础。IEC 60870-5-104/101协议作为经典远动通信标准,采用客户端/服务器架构,支持遥测、遥信等数据传输。而IEC 61850标准则通过面向对象建模和SCL语言实现了设备互操作性。这两种协议在实际工程中常配合使用,104协议用于站控层通信,61850则应用于过程层。理解SCL模型文件结构和协议映射原理,对实现智能变电站的配置与调试至关重要。本文通过典型工程案例,详解协议转换和模型配置的最佳实践。

weixin_31155097的博客 361

labview高低拼接的理解

计算机的一个字节由8位组成,无符号的8位整形表示的范围为0~255,范围太小了,所以用双字节,即16位整形表示更大范围的数字0 ~65535。2.labview中的高低拼接实质是高8位字节左移8位与低8位字节相加,结果是双字节整形。

qwerqwerdhr的博客 839

Netty核心架构与实战:从高性能网络编程到MQTT消息代理实现

网络编程是构建分布式系统的基石,其核心在于高效处理并发连接与数据传输。Java NIO提供了非阻塞I/O能力,但直接使用API复杂度高,易出错。Netty作为异步事件驱动框架,通过Reactor线程模型与责任链模式,将底层多路复用逻辑封装,实现了高性能、高并发的网络通信能力。其核心组件如ByteBuf提供高效内存管理,ChannelFuture支持异步操作,编解码器简化协议处理,这些特性使其在RPC框架、消息中间件等场景广泛应用。本文以构建MQTT消息代理为例,深入解析Netty如何处理MQTTMessag

weixin_33881140的博客 385

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

2.4 java面试题:Netty

Netty 是一个,用于快速开发高性能、高可靠性的网络 IO 程序。它在 Java 领域中的地位,就像“网络编程的 Spring”,几乎统治了所有需要自定义协议的中间件和分布式组件。老练的 Java 工程师说 Netty,不仅要讲“是什么”,还要讲清它,以及。

你是人间四月天 220

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Netty Tutorial Part 1: Introduction to Netty [z]

Netty Tutorial, Part 1: Introduction to Netty Update:  Part 1.5 Has Been Published: Netty Tutorial Part 1.5: On Channel Handlers and Channel OptionsFrom the Netty web site:"Netty is a NIO client serv...

weixin_33896726的博客 524

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Java网络IO模型演进全解析:从BIO、NIO到AIO,手写Reactor模型并剖析Netty核心架构

NIO(Non-blocking I/O,非阻塞IO)是Java 1.4引入的新I/O模型,解决了BIO在高并发场景下的性能瓶颈。NIO的核心思想是非阻塞和事件驱动,通过少量线程即可管理大量连接。异步非阻塞:基于事件驱动模型,使用少量线程即可处理大量并发连接高性能:通过零拷贝、内存池、对象池等技术优化,性能远超传统BIO/NIO高可扩展性:模块化设计,支持自定义协议和处理器协议丰富:内置HTTP、WebSocket、Protobuf、Redis等多种协议支持社区活跃。

weixin_42553604的博客 330

从零手写分布式任务调度与Netty网络框架:深度解析核心原理与实战

分布式任务调度是构建高可用、可扩展后端系统的关键技术,其核心在于协调多个节点有序、可靠地执行定时或异步任务。其实现原理通常围绕任务编排、状态管理、故障转移与负载均衡展开。在Java生态中,XXL-JOB作为广泛应用的调度框架,其设计体现了这些核心思想。而高性能的网络通信则是分布式系统交互的基石,Netty通过其Reactor线程模型和高效的ByteBuf内存管理,为高并发场景提供了底层支撑。理解这两者的底层实现,对于深入掌握分布式系统架构、优化应用性能具有重要价值。本文聚焦于一个教学级的开源项目,它通过从零

weixin_33910137的博客 873
上一篇: Netty(6)-客户端登陆并与服务端收发信息
下一篇: Spring Framework(8)-两百行代码实现简单IoC容器
BoringRong
BoringRong 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 2万+粉丝 386原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

BoringRong

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

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

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

打赏作者

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

抵扣说明:

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

余额充值