Vert.x + Protobuf二进制协议解析

Vert.x集成gRPC实现消息发送:从proto设计到流式控制实战 现代分布式系统中,服务间的通信方式直接决定整体架构的效率和稳定性。RPC框架通过接口约束与高效序列化机制,解决了HTTP语义模糊和流式支持不足等问题。gRPC基于HTTP/2的多路复用与protobuf二进制协议,在低延迟、高吞吐场景下优势明显,其四种调用模型可覆盖请求-应答、客户端流、服务端流及双向流等典型模式。Vert.x作为响应式框架,事件循环模型与gRPC的异步交互天然契合,两者结合能构建出弹性可靠的消息推送通道。针对消息发送在生产环境中遇到的连接管理、超时重试、背压控制和资源回收等坑点,本文以Ve 阅读详情

这一期介绍如何解析二进制私有协议。

先说几句题外话,就是绝大多数情况下,可能根本用不着使用私有二进制协议,除非你的业务对性能极其敏感,否则HTTP足矣。

协议

我们的协议非常简单,先是一个4字节的整数表示数据长度,然后紧接着就是protobuf序列化后的字节数组。proto定义如下:

syntax = "proto2";
package cn.fh.vertx.demo.proto;

option java_multiple_files = true;

message Message {
    required int32 type = 1;
    required string content = 2;
}

在实际业务场景中,消息格式的定义是有讲究的,这里不深究,重点在于vert.x解析。

RecordParser

Vert.x中只有一个二进制协议解析辅助类,即RecordParser,可以很好的解决粘包/拆包问题。它有两种工作模式,一是delimited mode, 即通过固定分隔符分隔数据包,这种用的其实比较少;二是fixed size mode,即固定数据长度模式。诈一看可能很多人会有疑虑,多数协议都是可变长度的啊,这两种模式看起来都不能满足要求。其实模式二支持在处理的过程中随时动态的改变size值,这样就可以间接完成对变长协议的解析。

首先,RecordParser有两类Builder方法,RecordParser.newDelimited()和RecordParser.newFixed(4),分别对应上面的模式一和模式二。构造完成以后,跟其它vert.x的方法一样,我们需要定义一个Handler, RecordParser每分割出一段字节数组都会调用一次Handler,业务逻辑处理就在此Handler中进行。对于上面"长度 + 数据"的协议,我们可以首先构造一个以4字节为单位的RecordParser,在收到长度数据后,再动态将解析器修改成指定长度状态,从而完成对数据部分的分割。代码示例如下:

// 先以长度4构造对象
        RecordParser parser = RecordParser.newFixed(4);

        // 设置处理器
        parser.setOutput(new Handler<Buffer>() {
            // 表示当前数据长度
            int size = -1;

            @Override
            public void handle(Buffer buffer) {
                // -1表示当前还没有长度信息,需要从收到的数据中取出长度
                if (-1 == size) {
                    // 取出长度
                    size = buffer.getInt(0);
                    // 动态修改长度
                    parser.fixedSizeMode(size);

                } else {
                    // 如果size != -1, 说明已经接受到长度信息了,接下来的数据就是protobuf可识别的字节数组
                    byte[] buf = buffer.getBytes();
                    Message msg = null;
                    try {
                        msg = Message.parseFrom(buf);
                    } catch (InvalidProtocolBufferException e) {
                        System.out.println(e.getMessage());
                        socket.close();
                        return;
                    }
                    
                    System.out.println(msg);
                    // 处理完后要将长度改回4
                    parser.fixedSizeMode(4);
                    // 重置size变量
                    size = -1;
                }
            }
        });

虽然用起来比较别扭,但这的确是标准使用方法。

如果表示长度的数据不是从0开始的,比如0 ~ 3为消息类型,4 ~ 7才表示body的长度,那么可以在构造解析器时先将长度设为8, 然后取后4字节做为新的长度即可。

其实这个类所做的事正是Netty里LengthFieldBasedFrameDecoder的功能,希望Vert.x以后能直接提供好类似的处理器,不要让用户再手动取长度了,毕竟低层的Netty都支持,你更高级的封装怎么可以没有呢。

这个RecordParser怎么用呢?看一下完整的代码吧:

        Vertx vertx = Vertx.vertx();
        
        // 创建TCP Server
        NetServer server = vertx.createNetServer();
        // 设置Handler
        server.connectHandler(socket -> {
            // 构造parser
            RecordParser parser = RecordParser.newFixed(4);
            parser.setOutput(new Handler<Buffer>() {
                int size = -1;

                @Override
                public void handle(Buffer buffer) {
                    if (-1 == size) {
                        size = buffer.getInt(0);
                        parser.fixedSizeMode(size);
                        
                    } else {
                        byte[] buf = buffer.getBytes();
                        Message msg = null;
                        try {
                            msg = Message.parseFrom(buf);
                        } catch (InvalidProtocolBufferException e) {
                            System.out.println(e.getMessage());
                            socket.close();
                            return;
                        }
                        parser.fixedSizeMode(4);
                        size = -1;
                    }
                }
            });

            socket.handler(parser);
        });
        
        // 监听
        server.listen(8008, "localhost", res -> {
            if (res.succeeded()) {
                System.out.println("tcp server is listening at 8008");

            } else {
                System.out.println(res.cause());
            }
        });

写起来会有一点点奇怪,适应就好。

carlaviz实时可视化原理:UDP+HTTP+WebSocket混合架构解析 自动驾驶仿真可视化是连接算法与物理世界的关键桥梁,其核心在于低延迟、高保真地呈现传感器原始数据流。CARLA等仿真器输出的二进制遥测数据(如激光雷达点云、相机图像、车辆位姿)需经协议解析、坐标系对齐、GPU加速渲染等多层转换,才能在浏览器中实现60fps交互式三维可视化。carlaviz作为轻量级Web中间件,摒弃传统全WebSocket方案,创新采用UDP承载高带宽传感器数据、HTTP同步元信息、WebSocket传递控制信令的混合架构,在Intel核显设备上稳定渲染220万点/帧的128线激光雷达——这 阅读详情

相关推荐

多Agent框架选型指南:从需求分析到实施落地

多Agent系统作为分布式计算和人工智能交叉领域的关键技术,通过自治Agent的协同工作解决复杂问题。其核心原理基于消息传递和分布式协调,采用Actor模型或发布订阅等通信范式。在技术价值层面,多Agent框架能显著提升系统扩展性和容错能力,特别适合实时交易、IoT设备管理等需要高并发的场景。以金融系统为例,采用Akka框架可实现50ms内的交易响应,而MQTT协议则能支持海量物联网设备连接。本文提供的选型决策树和性能评测方法,结合Kubernetes和Service Mesh等云原生技术,帮助开发者规避常

weixin_34221773的博客 268

Vert.x 3学习笔记---13

这一部分可能会有多个主题。Record Parser协议解析buffer1:HELLO\nHOW ARE Y buffer2:OU?\nI AM buffer3: DOING OK buffer4:\n像上例,是一个简单的ASCII文件的协议,以’\n’分割。解析后的结果为:buffer1:HELLO buffer2:HOW ARE YOU? buffer3:I AM DOING OK具体的代码如下

4696

Java自定义协议的10大必杀技:为什么你的代码像发呆的蜗牛?

摘要: 本文揭秘10大Java网络编程性能优化技巧,助力代码实现"光速"通信: 协议设计:类比快递单结构,规范消息格式 安全校验:魔数+版本号防伪防过期 二进制编解码:比JSON体积减少70% Vert.x框架:异步非阻塞处理百万并发 Netty定制:灵活扩展各类协议 Protobuf压缩:消息体体积缩小80% 心跳机制:30秒间隔保活连接 AES加密:保障传输安全 异常熔断:自动重发+线程中断处理 零拷贝优化:减少内存复制提升吞吐 采用Vert.x+自定义二进制协议可轻松构建高性能聊天

java专栏 696

Vertx利用RecordParser解决TCP传输粘包半包问题

通过响应TCP服务端缓冲池的变化来动态分割TCP报文,RecordParser提供了分割字节数组的功能。

weixin_45957747的博客 478

JetLinks工业物联网平台实战解析:协议接入、响应式架构与边缘部署

工业物联网平台需兼顾设备协议兼容性、高并发实时处理与私有化部署能力。JetLinks以Spring Boot 3 WebFlux实现非阻塞通信,支撑数千设备毫秒级连接;通过模块化协议适配层(Modbus/OPC UA/MQTT)统一抽象设备接入逻辑,解决OT侧碎片化难题;结合Vue 3组合式函数实现设备状态精准驱动的动态可视化,并依托Docker多阶段构建与jlink定制JRE达成45MB轻量镜像,满足产线离线部署要求。其源码结构即工程实践说明书,适用于毕业设计验证、中小企业私有化物联网落地及工业系统集成开

weixin_34212762的博客 390

VertX-ProtoBuf:使用VertX测试协议缓冲区[JAVA]

Vert.x-ProtoBuf 使用VertX测试协议缓冲区[JAVA] Vert.x是用于在JVM上构建响应式应用程序的工具包。 协议缓冲区是一种与语言无关,与平台无关的可扩展机制,用于序列化结构化数据。 该示例部署了两个顶点,它们之间传递了一个简单的对象。 数据使用协议缓冲区进行编码,并使用vert.x事件总线发送。 HelloRequest用于定义具有单个属性的简单对象:name HelloWorldProto由protoc.exe 4.3.0从proto文件Simple.proto自动生成。 SpeakerVerticle生成一个HelloRequest对象,并使用生成的协议缓冲区HelloWorldProto.HelloRequest.Build将其转换为消息。 ListenerVerticle通过vert.x的事件总线接收消息,然后convert根据接收到的消息实

TCP粘包问题及各方解决方案

TCP粘包问题

John_ToStr的博客 1029

RecordParser:基于简单表达式树的解析器,专注于高性能,可扩展性和简单用法

RecordParser-简单,快速,可扩展的记录解析 RecordParser是基于表达式树的解析器,可帮助您编写可维护,快速且简单的解析器。通过自动化不相关的代码,开发人员可以更轻松地进行解析,从而使开发人员可以专注于映射的本质。 RecordParser是.NET Core的零分配写入器/读取器解析器 它支持.NET Core 2.1、3.1、5.0和.NET Standard 2.1 它具有最小的堆分配,因为它大量使用了类型, 类型是一种新的.NET类型,旨在具有高性能并减少内存分配 它具有更高的性能,因为相关代码是使用生成的,一旦编译就几乎像手写代码一样 它支持解析类和结构类型,而无需 它很灵活:您可以选择最方便的方式来配置每个解析器:索引配置或顺序配置 它是可扩展的:您可以使用lambda / delegates完全自定义您的解析 它甚至更具扩展性,因为开发人员可以轻松地使用

byte数组转二进制_Vert.x + Protobuf二进制协议解析

这一期介绍如何解析二进制私有协议。先说几句题外话,就是绝大多数情况下,可能根本用不着使用私有二进制协议,除非你的业务对性能极其敏感,否则HTTP足矣。协议我们的协议非常简单,先是一个4字节的整数表示数据长度,然后紧接着就是protobuf序列化后的字节数组。proto定义如下:syntax 在实际业务场景中,消息格式的定义是有讲究的,这里不深究,重点在于vert.x解析。RecordParserV...

weixin_39706127的博客 504

jmeter 5.1.1 tcp链接 发送protobuf消息到服务端,并返回结果的demo

jmeter 5.1.1 版本。maven项目。服务端 vertx+kotlin。 实现jmeter tcp链接 发送protobuf消息到服务端,并返回结果的demo。具体看里面的doc目录的说明。

生成protobuf协议工具

生成protobuf协议工具

微服务通信模式终极指南:HTTP REST vs Event Bus vs gRPC 全面对比

在当今云原生架构中,微服务通信模式的选择直接影响系统性能、可扩展性和开发效率。本文将深入分析三种主流微服务通信模式——HTTP REST、Event Bus和gRPC的技术特性、适用场景及性能表现,帮助开发者为Vert.x微服务架构做出最佳技术决策。 ## 微服务通信架构概览 📊 现代微服务架构中,服务间通信是核心挑战之一。vertx-blueprint-microservice项目展示了一

gitblog_00050的博客 335

Vert.x!这是目前最快的 Java 框架

如果您搜索“最佳网络框架”,您可能会偶然发现Techempower基准测试,其中排名超过300个框架,在那里你可能已经注意到Vert.x是排名最高的。Vert.x是一个多语言 Web 框架,它支持Java,Kotlin,Scala,Ruby和Javascript支持的语言之间的共同功能。无论语言如何,Vert.x都在Java虚拟机(JVM)上运行。模块化和轻量级,它面向微服务开发。Techempower基准测试衡量从数据库更新,获取和交付数据的性能。每秒提供的请求越多越好。在这种涉及很少计算的IO场景中,任何非阻塞框架都会有优势。近年来,这种范式几乎与Node.js不可分割,Node.js通过

2014.7.21

上次测试vertx用的是普通的

killer0128的专栏 461

Unity 2021 LTS安装避坑指南:从下载到第一个3D项目的完整流程

本文提供了一份详尽的Unity 2021 LTS安装与首个3D项目创建指南。内容涵盖从Unity Hub下载、版本选择、模块安装避坑,到编辑器界面解析、创建旋转立方体脚本的完整流程,旨在帮助初学者快速搭建稳定开发环境并上手核心操作。

mango的博客 308

DIY T12烙铁头驱动难题:用几个电容二极管,搞定NMOS上管驱动(附Multisim仿真)

本文详细介绍了如何利用电荷泵电路解决DIY T12烙铁头驱动中的NMOS上管驱动难题。通过巧妙组合电容和二极管,构建低成本高效的升压电路,实现栅极高压驱动需求。文章包含具体电路设计、元件选型建议、实际搭建注意事项以及Multisim仿真验证,为电子爱好者提供了一套完整的解决方案。

weixin_33640562的博客 334

使用gRPC构建真实世界的微服务

早期的微服务实现主要使用REST架构作为事实上的通信技术。通常,RESTful服务对于面向外部的服务会很有用,这些服务直接暴露给消费者。它们是基于传统的文本消息传递(JSON、XML、基于HTTP的CVS等),但这些消息主要是面向人类的,并不是服务间通信的理想选择。除了使用基于文本的消息传递协议,我们还可以使用针对服务间通信而优化的二进制协议。云原生计算基金会(CNCF)的gRPC(gRPC远程过...

weixin_34267123的博客 253

Cisco三层交换机的详细配置

** 本文适用于新手小白以及微微基础的同学来用于参考,实验是在Cisco Packet Tracer Student 进行,实验最终效果如图所示,所有命令配置与图中的一致。 使用到的机器型号为:五台电脑,一台服务器,三个普通交换机(2960型号),一个三层交换机(3560-24PS),两台普通服务器(2811) 文章目录一、什么是三层交换机二、配置交换机步骤1.配置二层交换机2.配置三层交换机3.配置两台路由器以及最后一台电脑 一、什么是三层交换机 1.三层交换机 = 三层路由+二层交换机 2.工作在

真正的大师,永远都怀着一颗学徒的心。 4万+

Java网络编程核心技术:从Socket到Netty实战

网络编程是现代分布式系统的基础能力,其核心在于通过TCP/IP协议栈实现设备间通信。Java作为企业级开发的主流语言,提供了从基础Socket到高性能NIO的完整网络编程体系。理解阻塞IO与非阻塞IO的区别、掌握多路复用技术是构建高并发网络应用的关键。在实际工程中,网络编程技术广泛应用于即时通讯、微服务调用、文件传输等场景。通过合理使用连接池、优化缓冲区以及选择适当的IO模型,可以显著提升系统吞吐量。随着云原生技术的发展,Java网络编程正向着响应式、异步非阻塞的方向演进,Netty等框架已成为处理高并发网

weixin_33690963的博客 311

STM32读取BQ40Z50的数据

TI电池管理芯片BQ40Z50,通信协议是SMBUS,类似IIC,速率要求10-100KHz   用的STM32F103的硬件IIC读取电池的各种数值,源代码如下: ​ #include "iic.h" #include "stdio.h"  //***************************************************** // IIC2初始化函数:初始化ST...

百步登峰的博客 1万+

STM32F407 CubeMX UART DMA高效解析BNO085九轴数据

本文详细介绍了如何在STM32F407平台上使用CubeMX配置UART和DMA高效解析BNO085九轴传感器数据。通过DMA循环接收机制实现低CPU占用的实时数据采集,并分享数据解析技巧、错误处理及实战调试经验,为嵌入式开发者提供完整解决方案。

o4p5q6r7s的博客 234

为什么选择Netty作为基础通信组件?

以下内容根据网上资料和自己整理总结而成 一、什么是Netty? Netty是一个高性能 事件驱动、异步非堵塞的IO(NIO)Java开源框架,Jboss提供,用于建立TCP等底层的连接,基于Netty可以建立高性能的Http服务器,快速开发高性能、高可靠性的网络服务器和客户端程序。支持HTTP、 WebSocket 、Protobuf、 Binary TCP |和UDP,Netty已经被很多高...

勇往直前的专栏 1038

Autodesk Revit软件二次开发:Revit二次开发中的插件设计与实现

在 Revit 中,族是构成建筑模型的基本单元,可以是门窗、家具等。通过自定义族,可以创建符合特定需求的建筑构件。参数化设计允许族的尺寸、形状等属性根据参数变化而变化。使用 Revit API 创建自定义族涉及多个步骤,包括定义族类型、设置参数、创建几何形状等。// 创建族文档// 定义参数Parameter param = family.FamilyManager.AddParameter("Width", BuiltInParameterGroup.PG_LENGTH, "宽度");

kkchenjj的博客 2228
上一篇: Java异常处理使用Throwable而不是Exception
下一篇: 用Go写业务系统需要制造哪些轮子?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值