SpringBoot整合阻塞式TCP服务器长连接(BIO方式)

SpringBoot整合TCP服务器长连接(BIO方式)

前言: 自学java以来,这是第一次写博客,是为了记录自己在工作中积累的经验和成果,希望可以坚持下来。看到的也就当个参考,自己技术也不是很好,还有很多需要学习的地方,有不对的地方,希望大牛们多多指点。

​ 刚从事开发不久,接到一个任务,是将原来项目中的 mqtt 连接改为 tcp 长连接,所以需要在 SpringBoot 中整合 tcp 服务器,并实现和其他设备的长连接,与设备之间进行交互。在查阅很多网上的资料后,发现有一个Netty的框架可以做到高效稳定的连接,但是由于任务完成有时限,而我也没有学习过 Netty,NIO 编程在自学 java 时也没有深入了解,所以就先使用了最原始的 BIO 来编写了服务端。在写代码的同时,也在网上找了韩顺平老师的 Netty 课程自学,最后也是将 BIO 这种方式转成了 Netty。后面有空也会将 SpringBoot 整合 Netty 记录下来。

BIO 基本介绍

BIO(Blocking I/O):同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理。

​ Java BIO 工作机制:
Java BIO 工作机制


TCP 服务器启动类 —— SocketRunner

​ 该类实现了 CommandLineRunner 接口,这个接口字面意思是命令行启动,会随着 SpringBoot 启动,重写该类的 run 方法即可。启动后循环监听是否有新的连接接入,若有新的连接则创建一个线程对这个连接进行处理。

提示:如果要处理并发量较大的 TCP 连接,推荐各位还是使用 NIO 或者 netty。

/**
 * TCP服务器启动类
 * @author Leaves Ye
 * @date Created on 14:40 2020/12/15
 * @since JDK 1.8
 */
@Component
public class SocketRunner implements CommandLineRunner {
   
    private final Logger logger = LoggerFactory.getLogger(SocketRunner.class);

    @Resource
    //tcp配置类,里面存放了监听的端口号
    private SocketConfig socketConfig;

    @Resource
    private ThreadPoolTaskExecutor socketTaskExecutor;
    
    @Override
    public void run(String... args) throws Exception {
   
        try (ServerSocket serverSocket = new ServerSocket(socketConfig.getPort())) {
   
            logger.debug("tcp服务器已启动,正在监听端口-->{}", socketConfig.getPort());
            while (true) {
   
                //获取连接socket对象
                Socket socket = serverSocket.accept();
                logger.debug("tcp获取连接,连接ip-->{}", socket.getInetAddress().getHostAddress());
                //将socket存放到SocketSend类中
                if (SocketSend.addSocket(socket)) {
   
                    //启动线程并传入socket对象,对连接到的socket进行处理
                    SocketRunnable socketRunnable = SpringUtil.getBean(SocketRunnable.class);
                    socketRunnable.setSocket(socket);
                    socketTaskExecutor.execute(socketRunnable);
                }
            }
        } catch (IOException e) {
   
            logger.error("tcp服务器异常,异常信息-->{}", e.getMessage());
        }
    }
}

TCP 消息发送类 —— SocketSend

​ TCP 通讯是属于全双工的通讯,也就是说在接收的同时也是可以进行发送的,所以我将获取到的 Socket 对象用一个 Map 集合进行存储,Key 是 Socket 的 ip 地址,Value 是 Socket 对象,并且限制每个 ip 只能建立唯一的一个连接

​ 该对象中封装了添加和移除 Socket 对象的方法,并且封装向对应 ip 连接发送消息的方法。

​ 由于是私有协议,所以我将数据封装成了两个对象:TcpPackage 和 TcpMessage。

​ TcpPackage:私有协议传输的最小单位,通过包头信息可将多个包组合成 TcpMessage 对象,获得传输真正需要的数据。

​ TcpMessage:私有协议所要传输的真实数据对象,由多个 TcpPackage 合并成。

​ 由于发送的最小单位是 TcpPackage,如果有多个线程调用同一个 Socket 对象进行数据传输,由于 TCP 传输时流的方式,同时传输则会造成数据混杂,所以当进行 TcpPackage 传输的时候,我加上了同步锁,锁对象则是当前传输的 Socket 对象,防止数据混乱。

/**
 * TCP消息发送类
 *
 * @author Leaves Ye
 * @date Created on 11:17 2020/12/18
 * @since JDK 1.8
  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值