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()
        );
    }
}

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

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

相关推荐
葫芦和十三17 小时前
图解 MongoDB 05|文档模型设计:内嵌 vs 引用,反范式不是免费午餐
后端·mongodb·agent
不能放弃治疗20 小时前
单 Agent 实现模式
后端
IT_陈寒1 天前
Redis内存爆了,原来我漏掉了这个致命配置
前端·人工智能·后端
小bo波1 天前
从"任意文件复制"深挖Java I/O:字符流与字节流的本质抉择
java·nio·io流·后端开发·文件复制
fliter1 天前
最后一块拼图:用 bitvec 构造 IPv4 包,真正做出自己的 Ping
后端
用户3521802454751 天前
🎆从 Prompt 到 Skill:让 Spring AI Agent 学会"装新技能"
人工智能·spring boot·ai编程
fliter1 天前
用 Rust 解析并生成 ICMP 包:checksum、nom 与 cookie-factory
后端
蝎子莱莱爱打怪1 天前
XZLL-IM干货系列 03|消息 ID 设计:一个 UUID 搞不定的事,我用两个 ID 解决了
后端·面试·开源
fliter1 天前
从 panic 到 Result:用 Rust 重新整理一个 ping 项目的错误处理
后端
森蓝情丶1 天前
我给 AI 搭了个法庭:一个前端仔的 LangGraph 实战全记录
前端·后端