springboot 作为客户端接收服务端的 tcp 长连接数据,并实现自定义结束符,解决 粘包 半包 问题

博主最近的项目对接了部分硬件设备,其中有的设备只支持tcp长连接方式传输数据,博主项目系统平台作为客户端发起tcp请求到设备,设备接收到请求后作为服务端保持连接并持续发送数据到系统平台。

1.依赖引入

连接使用了netty,如果项目中没有就先引入:

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.69.Final</version>
</dependency>

2.创建客户端

java 复制代码
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;

/**
 * @author GBX
 * @description tcp长连接客户端
 * @date 2024/5/29 15:11
 */
@Slf4j
public class NettyTcpClient {

    private final Bootstrap bootstrap;
    private final EventLoopGroup group;
    private Channel channel;

    public NettyTcpClient(String host, int port) {
        group = new NioEventLoopGroup();
        bootstrap = new Bootstrap();
        bootstrap.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {
            @Override
            public void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                //添加自定义结束规则
                pipeline.addLast(new DelimiterBasedFrameDecoder(1024, ByteBufAllocator.DEFAULT.buffer().writeBytes("|".getBytes(StandardCharsets.UTF_8))));
                //添加自定义消息处理器
                pipeline.addLast(new TcpClientHandler());
            }
        });

        try {
            channel = bootstrap.connect(host, port).sync().channel();
            log.info("NettyTcpClient ===》 success");
        } catch (Exception e) {
            log.error("NettyTcpClient-发生异常, 信息:", e);
        }
    }

    public void close() {
        if (channel != null) {
            channel.close();
        }
        group.shutdownGracefully();
    }

    public static class TcpClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
            //处理接收到的数据
            System.out.println("Received data ===>: " + msg.toString(StandardCharsets.UTF_8));
        }

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

如上代码中所示,博主使用了 "|" 作为结束符,使用结束符可以有效地解决tcp数据读取的粘包 半包问题。

3.设置配置类以进行自启动

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author GBX
 * @description tcp长连接配置类
 * @date 2024/5/29 15:14
 */
@Configuration
public class NettyClientConfig {

    @Bean(destroyMethod = "close")
    public NettyTcpClient nettyTcpClient() {
        NettyTcpClient client = new NettyTcpClient("127.0.0.1", 4001);
        // 启动客户端连接
        return client;
    }
}

4.效果测试

启动项目,发现客户端连接远程成功:

远程服务器端,这里使用的是 NetAssist 工具进行模拟(注意:该工具在springboot项目启动前已经提前启动了服务器模式进行了端口监听,可以看到项目启动后进来一个连接):

如上图所示,在8 和 10 后分别由一个结尾符,在工具上发送数据:

在springboot控制台可以看到打印的信息为两条:

工具可以在网盘下载:

链接: https://pan.baidu.com/s/1UccmnEL4VktHTHL7P_2V_g?pwd=6fcw 提取码: 6fcw

相关推荐
王ASC9 小时前
SpringMVC的URL组成,以及URI中对/斜杠的处理,解决IllegalStateException: Ambiguous mapping
java·mvc·springboot·web
撒呼呼9 小时前
# 起步专用 - 哔哩哔哩全模块超还原设计!(内含接口文档、数据库设计)
数据库·spring boot·spring·mvc·springboot
灰色孤星A16 小时前
瑞吉外卖项目学习笔记(四)@TableField(fill = FieldFill.INSERT)公共字段填充、启用/禁用/修改员工信息
java·学习笔记·springboot·瑞吉外卖·黑马程序员·tablefield·公共字段填充
武子康2 天前
Java-31 深入浅出 Spring - IoC 基础 启动IoC XML与注解结合的方式 配置改造 applicationContext.xml
java·大数据·spring·mybatis·springboot
synda@hzy3 天前
MONI后台管理系统-系统三员的设计
java·springboot·等级保护·三员管理
灰色孤星A3 天前
瑞吉外卖项目学习笔记(二)Swagger、logback、表单校验和参数打印功能的实现
springboot·logback·swagger·瑞吉外卖·切面编程·表单校验·黑马程序员
langzitianya3 天前
RestTemplate实时接收Chunked编码传输的HTTP Response
springboot·stream·resttemplate·chunked·流式
武子康3 天前
Java-30 深入浅出 Spring - IoC 基础 启动IoC 纯XML启动 Bean、DI注入
xml·java·开发语言·后端·spring·mybatis·springboot
Moshow郑锴4 天前
Spring Boot中CollectionUtils怎么用
springboot·数组·collectionutil
武子康4 天前
大数据-253 离线数仓 - Airflow 任务调度 核心概念与实际案例测试 Py脚本编写
java·大数据·数据仓库·hive·hadoop·springboot