springboot框架对接物联网,配置TCP协议依赖,与设备通信,让TCP变的如此简单

最近在使用 Spring Boot 对接物联网设备,需要通过 TCP 协议进行通信。调研过程中发现,如果使用 Netty 框架并集成到 Spring Boot 中,配置和维护相对较为复杂。综合考虑后,最终选择了 Spring Integration 提供的 TCP/UDP 模块来实现相关功能,整体集成更加简洁,也更符合 Spring 生态的使用习惯。

第一步:

引入依赖

bash 复制代码
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-ip</artifactId>
</dependency>

第二步:

提供两个tcp服务端类文件,这两个类文件大家按需选择即可。

第一个类文件:

单向接收tcp客户端数据:

bash 复制代码
package com.testweb.testweb.tcp.web;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.ip.tcp.TcpReceivingChannelAdapter;
import org.springframework.integration.ip.tcp.connection.AbstractServerConnectionFactory;
import org.springframework.integration.ip.tcp.connection.TcpNioServerConnectionFactory;
import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;

import java.nio.charset.StandardCharsets;

@Slf4j
@Configuration
public class TcpServerConfig {

    @Value("${tcp.server.port:7788}")
    private int port;

    /**
     * 1. TCP 连接工厂(服务端)
     */
    @Bean
    public AbstractServerConnectionFactory serverConnectionFactory() {
        TcpNioServerConnectionFactory factory =
                new TcpNioServerConnectionFactory(port);

        // 关键:拆包 / 粘包解决方案(行结束符)
        // 按换行符 (\r\n 或 \n) 拆包,常用于文本协议
        ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer();

        // 二进制协议示例:长度头 + 消息内容(常用于物联网)
        // ByteArrayLengthHeaderSerializer serializer =
        //         new ByteArrayLengthHeaderSerializer();

        factory.setSerializer(serializer);
        factory.setDeserializer(serializer);
        factory.setUsingDirectBuffers(true);
        return factory;
    }

    /**
     * 2. 接收同步通道
     */
    @Bean
    public MessageChannel tcpReceiveChannel() {
        return new DirectChannel();
    }

    /**
     * 3. TCP 入站适配器(只接收)
     */
    @Bean
    public TcpReceivingChannelAdapter tcpInboundAdapter(
            AbstractServerConnectionFactory factory,
            MessageChannel tcpReceiveChannel) {

        TcpReceivingChannelAdapter adapter =
                new TcpReceivingChannelAdapter();
        adapter.setConnectionFactory(factory);
        adapter.setOutputChannel(tcpReceiveChannel);
        return adapter;
    }

    /**
     * 4. 业务处理器(单向接收,不能给客户端回复)
     */
    @ServiceActivator(inputChannel = "tcpReceiveChannel")
    public void handleMessage(Message<byte[]> message) {
        String data =
                new String(message.getPayload(), StandardCharsets.UTF_8);
        String connectionId =
                (String) message.getHeaders().get("ip_connectionId");

        log.info("收到 TCP 数据: {}", data);
        log.info("来自连接: {}", connectionId);

        // TODO 业务逻辑处理
    }
}

第二个类文件:

双向类文件:接收客户端消息并回复

bash 复制代码
package com.testweb.testweb.tcp.web;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.ip.tcp.TcpReceivingChannelAdapter;
import org.springframework.integration.ip.tcp.TcpSendingMessageHandler;
import org.springframework.integration.ip.tcp.connection.AbstractServerConnectionFactory;
import org.springframework.integration.ip.tcp.connection.TcpNioServerConnectionFactory;
import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;

import java.nio.charset.StandardCharsets;

@Slf4j
@Configuration
public class TcpServerReplyConfig {

    @Value("${tcp.server.reply.port:7799}")
    // 与单向服务端端口区分
    private int port;

    // 回复通道
    @Autowired
    @Qualifier("tcpReplySendChannel")
    private MessageChannel tcpReplySendChannel;

    /**
     * 1. TCP 连接工厂(服务端)
     */
    @Bean
    public AbstractServerConnectionFactory replyServerConnectionFactory() {
        TcpNioServerConnectionFactory factory =
                new TcpNioServerConnectionFactory(port);

        // 关键:拆包 / 粘包解决方案
        // 使用换行符拆包(文本协议)或长度头(物联网二进制协议)
        ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer();
        // ByteArrayLengthHeaderSerializer serializer =
        //         new ByteArrayLengthHeaderSerializer();

        factory.setSerializer(serializer);
        factory.setDeserializer(serializer);
        factory.setUsingDirectBuffers(true);
        return factory;
    }

    /**
     * 2. 接收通道
     */
    @Bean
    public MessageChannel tcpReplyReceiveChannel() {
        return new DirectChannel();
    }

    /**
     * 3. TCP 入站适配器(接收客户端消息)
     */
    @Bean
    public TcpReceivingChannelAdapter tcpReplyInboundAdapter(
            AbstractServerConnectionFactory replyServerConnectionFactory,
            MessageChannel tcpReplyReceiveChannel) {

        TcpReceivingChannelAdapter adapter =
                new TcpReceivingChannelAdapter();
        adapter.setConnectionFactory(replyServerConnectionFactory);
        adapter.setOutputChannel(tcpReplyReceiveChannel);
        return adapter;
    }

    /**
     * 4. TCP 出站通道(用于回复客户端)
     */
    @Bean("tcpReplySendChannel")
    public MessageChannel tcpReplySendChannel() {
        return new DirectChannel();
    }

    /**
     * 5. 出站适配器(发送回复)
     */
    @Bean
    @ServiceActivator(inputChannel = "tcpReplySendChannel")
    public TcpSendingMessageHandler tcpReplySender(
            AbstractServerConnectionFactory replyServerConnectionFactory) {

        TcpSendingMessageHandler sender =
                new TcpSendingMessageHandler();
        sender.setConnectionFactory(replyServerConnectionFactory);
        return sender;
    }

    /**
     * 6. 业务处理器:接收客户端消息并回复
     */
    @ServiceActivator(inputChannel = "tcpReplyReceiveChannel")
    public void handleReplyMessage(Message<byte[]> message) {
        String data =
                new String(message.getPayload(), StandardCharsets.UTF_8);
        String connectionId =
                (String) message.getHeaders().get("ip_connectionId");

        log.info("收到客户端消息: {}", data);
        log.info("来自连接: {}", connectionId);

        // 业务逻辑处理完后发送回复
        String reply =
                "服务端已经收到消息,现在给客户端回复: " + data;

        tcpReplySendChannel.send(
                org.springframework.messaging.support.MessageBuilder
                        .withPayload(reply.getBytes(StandardCharsets.UTF_8))
                        .setHeader("ip_connectionId", connectionId)
                        .build()
        );
    }
}

这两个配置文件 大家可以按需选择。第一个类文件就是服务端只负责接收,不会给客户端反馈

第二个类文件,接收后会反馈,如果在使用中发现有需要完善的地方,也欢迎大家留言~

相关推荐
老毛肚20 分钟前
juc线程通信
java·开发语言·jvm
IT_陈寒25 分钟前
Redis的KEYS命令把我搞崩溃了,改用SCAN才活过来
前端·人工智能·后端
长不胖的路人甲1 小时前
SpringCloud 服务雪崩、熔断、降级
后端·spring·spring cloud
花颜yyds1 小时前
Java 开发基础速查手册
java
爱折腾的小黑牛2 小时前
小程序多人协作的权限设计:三级权限的实现
后端
没钥匙的锁12 小时前
05-Java面向对象构造器与封装
java·开发语言
aaPIXa6222 小时前
C++采样引导优化SPGO——比PGO更智能的编译器决策新方案
java·c++·人工智能
蓝银草同学2 小时前
Stream 实战:博客列表排序、过滤与分页(AI 辅助学习 Java 8)
java·前端·后端
某不知名網友3 小时前
C/C++动态内存管理,智能指针及RAlI思想。
java·c语言·c++
小小猪的春天3 小时前
AI 编程 30 天实验复盘:效率提升 65%,线上 bug 涨到 11 个,问题出在哪
后端