java-socket长连接demo体验

本文介绍了Java实现socket长连接的预研过程,通过BIO的多线程方案,实现了心跳机制、客户端身份验证、异常处理等功能。文章详细探讨了IO通讯模型,包括BIO、NIO和异步IO,并分享了一个简单的SpringBoot Socket Demo项目,供学习参考。
摘要由CSDN通过智能技术生成

一、前言

最近公司在预研设备app端与服务端的交互方案,主要方案有:

  • 服务端和app端通过阿里iot套件实现消息的收发;

  • 服务端通过极光推送主动给app端推消息,app通过rest接口与服务端进行交互;

  • 服务端与app通过mqtt消息队列来实现彼此的消息交互;

  • 服务端与app通过原生socket长连接交互。

虽然上面的一些成熟方案肯定更利于上生产环境,但它们通讯基础也都是socket长连接,所以本人主要是预研了一下socket长连接的交互,写了个简单demo,采用了BIO的多线程方案,集成了springboot,实现了自定义简单协议,心跳机制,socket客户端身份强制验证,socket客户端断线获知等功能,并暴露了一些接口,可通过接口简单实现客户端与服务端的socket交互。

Github源码: 

https://github.com/DavidDingXu/springboot-socket-demo

二、IO通讯模型

1. IO通讯模型简介

IO通讯模型主要包括阻塞式同步IO(BIO),非阻塞式同步IO,多路复用IO以及异步IO。

该部分内容总结自专栏文章: 

https://blog.csdn.net/yinwenjie/column/info/sys-communication/3

1.1 阻塞式同步IO

BIO就是:blocking IO。最容易理解、最容易实现的IO工作方式,应用程序向操作系统请求网络IO操作,这时应用程序会一直等待;另一方面,操作系统收到请求后,也会等待,直到网络上有数据传到监听端口;操作系统在收集数据后,会把数据发送给应用程序;最后应用程序受到数据,并解除等待状态。

BIO通讯示意图

1.2 非阻塞式同步IO

这种模式下,应用程序的线程不再一直等待操作系统的IO状态,而是在等待一段时间后,就解除阻塞。如果没有得到想要的结果,则再次进行相同的操作。这样的工作方式,暴增了应用程序的线程可以不会一直阻塞,而是可以进行一些其他工作。

非阻塞式IO示意图

1.3 多路复用IO(阻塞+非阻塞)

多路复用IO示意图

目前流程的多路复用IO实现主要包括四种:select、poll、epoll、kqueue。下表是他们的一些重要特性的比较:

1.4 异步IO

异步IO则是采用“订阅-通知”模式:即应用程序向操作系统注册IO监听,然后继续做自己的事情。当操作系统发生IO事件,并且准备好数据后,在主动通知应用程序,触发相应的函数。

异步IO示意图

和同步IO一样,异步IO也是由操作系统进行支持的。微软的windows系统提供了一种异步IO技术:IOCP(I/O Completion Port,I/O完成端口);

Linux下由于没有这种异步IO技术,所以使用的是epoll(上文介绍过的一种多路复用IO技术的实现)对异步IO进行模拟。

2. Java对IO模型的支持

  • Java对阻塞式同步IO的支持主要是java.net包中的Socket套接字实现;

  • Java中非阻塞同步IO模式通过设置serverSocket.setSoTimeout(100);即可实现;

  • Java 1.4中引入了NIO框架(java.nio包)可以构建多路复用、同步非阻塞IO程序;

  • Java 7中对NIO进行了进一步改进,即NIO2,引入了异步非阻塞IO方式。

由于是要实现socket长连接的demo,主要关注其一些实现注意点及方案,所以本demo采用了BIO的多线程方案,该方案代码比较简单、直观,引入了多线程技术后,IO的处理吞吐量也大大提高了。下面是BIO多线程方案server端的简单实现:

 
  1. public static void main(String[] args) throws Exception{

  2.        ServerSocket serverSocket = new ServerSocket(83);

  3.        try {

  4.            while(true) {

  5.                Socket socket = null;

  6.                socket = serverSocket.accept();

  7.                //这边获得socket连接后开启一个线程监听处理数据

  8.                SocketServerThread socketServerThread = new SocketServerThread(socket);

  9.                new Thread(socketServerThread).start();

  10.            }

  11.        } catch(Exception e) {

  12.            log.error("Socket accept failed. Exception:{}", e.getMessage());

  13.        } finally {

  14.            if(serverSocket != null) {

  15.                serverSocket.close();

  16.            }

  17.        }

  18.    }

  19. }

  20. @slf4j

  21. class SocketServerThread implements Runnable {

  22.  

  23.    private Socket socket;

  24.  

  25.    public SocketServerThread (Socket socket) {

  26.        this.socket = socket;

  27.    }

  28.  

  29.    @Override

  30.    public void run() {

  31.        InputStream in = null;

  32.        OutputStream out = null;

  33.        try {

  34.            in = socket.getInputStream();

  35.            out = socket.getOutputStream();

  36.            Integer sourcePort = socket.getPort();

  37.            int maxLen = 2048;

  38.            byte[] contextBytes = new byte[maxLen];

  39.            int realLen;

  40.            StringBuffer message = new StringBuffer();

  41.            BIORead:while(true) {

  42.                try {

  43.                    while((realLen = in.read(contextBytes, 0, maxLen)) != -1) {

  44.                        message.append(new String(contextBytes , 0 , realLen));

  45.                        /*

  46.                         * 我们假设读取到“over”关键字,

  47.                         * 表示客户端的所有信息在经过若干次传送后,完成

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值