背景

项目中经常会用到消息推送功能,关于推送技术的实现,我们通常会联想到轮询、comet长连接技术,虽然这些技术能够实现,但是需要反复连接,对于服务资源消耗过大,随着技术的发展,HtML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。本文将介绍如何采用websocket实现消息推送。

WebSocket简介

WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。浏览器和服务器仅需一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

协议原理

Websocket协议基于Http协议,针对Http协议进行了相关的改善,且Websocket协议也需要建立TCP连接来实现数据传输,具体实现如下图:

说明:

  • 客户端发起http请求,经过3次握手后,建立起TCP连接;http请求里存放WebSocket支持的版本号等信息,如:Upgrade、Connection、WebSocket-Version等。
  • 服务器收到客户端的握手请求后,同样采用HTTP协议回馈数据
  • 客户端收到连接成功的消息后,开始借助于TCP传输信道进行全双工通信.

WebSocket与HTTP协议的区别

相同点:都是一样基于TCP的,都是可靠性传输协议。都是应用层协议。

不同点:

  • WebSocket是双向通信协议,可以双向发送或接受信息,而HTTP是单向协议
  • WebSocket需要浏览器和服务器握手进行建立连接的,而http是浏览器发起向服务器的连接。

WebSocket特点

  • 建立在TCP协议之上,服务器端的实现比较容易。
  • 数据格式比较轻量,性能开销小,通信高效。
  • 支持多种数据格式,可以发送文本、二进制数据。
  • 客户端可以与任意服务器通信,无同源限制。

应用场景

  • 即时聊天通信
  • 在线协同编辑/编辑
  • 实时数据流的拉取与推送
  • 实时地图位置

系统集成Websocket

jar包引入

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.4.RELEASE</version>
    <relativePath/>
 </parent>
 
  <dependency>
      <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-websocket</artifactId>
  </dependency>

Websocket配置

@Configuration
public class WebSocketConfig
{
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

具体实现

@ServerEndpoint(value="/websocket/{uid}")
@Component
public class WebSocketServer
{
    private Logger logger = LoggerFactory.getLogger(WebSocketServer.class);
    
    private static final AtomicInteger onlineCount = new AtomicInteger(0);
    
    private static CopyOnWriteArraySet<Session> sessionSet = new CopyOnWriteArraySet<Session>();
    
    @OnOpen
    public void onOpen(Session session,@PathParam("uid") String uid) 
    {
        logger.info("open message uid:{}",uid);
        sessionSet.add(session);
        onlineCount.incrementAndGet();
        logger.info("窗口开始监听uid:{},当前在线人数:{}",uid,onlineCount);
    }
    
    @OnClose
    public void onClose(Session session) 
    {
        String sessionId=session.getId();
        logger.info("sessionid:{} close",sessionId);
        sessionSet.remove(this);
        int count=onlineCount.decrementAndGet();
        logger.info("有一连接关闭!当前在线人数为:{}",count);
    }

    @OnError
    public void onError(Session session, Throwable error) 
    {
        logger.error("消息发生错误:{},Session ID: {}",error.getMessage(),session.getId());
    }
    
   
    public void batchSendMesasge(String uid,String message) throws IOException 
    {
        logger.info("推送消息到窗口:{},推送内容:{}",uid,message);
        for(Session session:sessionSet){
            sendMessage(session, message);
        }
    }
    
    public void sendMessage(Session session, String message) throws IOException {
        
        if(session!=null)
        {
            synchronized (session) {
                session.getBasicRemote().sendText(message);
            }
        }
    }

}

说明: @OnOpen :当有新的WebSocket连接进入时调用 @OnClose:当有WebSocket连接关闭时调用 @OnError :当有WebSocket抛出异常时调用 @OnMessage:当接收到字符串消息时,对该方法进行回调

测试示例

@Controller
public class WebScoketController
{
   @Autowired
   private WebSocketServer webSocketServer;
  
    @ResponseBody
    @RequestMapping("/sendMessage")
    public String batchMessage(String uid,String message) 
    {  
        Map<String, String> map =new HashMap<String, String>();
        try 
        {
            map.put("code", "200");
            webSocketServer.batchSendMesasge(uid,message);
        } 
        catch (Exception e) 
        {
            map.put("code", "-1");
            map.put("message", e.getMessage());
        }
        return JSON.toJSONString(map);
    } 
    
    @GetMapping("/enter")
    public String enter() 
    { 
        return "webscoketTest.html";
    }
}

页面请求websocket

<!DOCTYPE HTML>
<html>
   <head>
   <meta charset="utf-8">
   <title>websocket test</title>
    
      <script type="text/javascript">
            if ("WebSocket" in window)
            {
            	console.log("您的浏览器支持 WebSocket!");
               
               var ws = new WebSocket("ws://127.0.0.1:9092/websocket/1234");
               console.log('ws连接状态:'   ws.readyState);
               
               //打开
               ws.onopen = function()
               {
                  ws.send("message test");
                  console.log("mesage sending");
               };
                
                //发送消息
               ws.onmessage = function (evt) 
               { 
                  var received_msg = evt.data;
                  alert(received_msg);
               };
                
                //关闭
               ws.onclose = function()
               { 
                  // 关闭 websocket
                  console.log("socket is close"); 
               };
            }
            
            else
            {
            	 console.log("您的浏览器不支持 WebSocket!");
            }
      </script>
   </head>
</html>

测试效果

启动程序:运行http://localhost:9092/enter 进入页面开启websocket。

用户发送消息:http://localhost:9092/sendMessage?uid=1235&message=this is message1

执行的结果如下:

 open message uid:1234
 [nio-9092-exec-2] c.s.f.w.controller.WebSocketServer: 窗口开始监听uid:1234,当前在线人数:1
 [nio-9092-exec-5] c.s.f.w.controller.WebSocketServer: 推送消息到窗口:1234,推送内容:this is message

以上就是SpringBoot WebSocket实现消息推送功能的详细内容,更多关于SpringBoot WebSocket消息推送的资料请关注Devmax其它相关文章!

SpringBoot+WebSocket实现消息推送功能的更多相关文章

  1. 五分钟学会HTML5的WebSocket协议

    这篇文章主要介绍了五分钟学会HTML5的WebSocket协议,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  2. 前端监听websocket消息并实时弹出(实例代码)

    这篇文章主要介绍了前端监听websocket消息并实时弹出,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. HTML5 WebSocket实现点对点聊天的示例代码

    这篇文章主要介绍了HTML5 WebSocket实现点对点聊天的示例代码的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  4. ios – Websockets可以在移动电话上工作吗?

    相关地,我怀疑长轮询客户端可能是实现类似功能的好方法,但我想知道我可能遇到的移动特定问题.到目前为止,我已经读过长时间的轮询请求可能会对电池寿命产生相当大的影响.我还听说iOS以某种方式限制了对单个服务器的连接数量,这可能是个问题.有没有人在使用实时组件的移动应用程序上工作?

  5. ios-swift,objective-c协议实现

    作为隐式解开的可选项.

  6. ios – 红蜘蛛代表没有被召集

    变量不是nil,我有一个很好的连接,url是正确的,但没有调用委托方法.我也正在实现WebSocketDelegate解决方法套接字应该是您的类的属性或变量,以确保它附近.如果仅在函数堆栈上分配它,它将超出范围,并且永远不会调用委托以下是我在项目中使用的代码,以防万一这是link到故事板,以防万一你想要

  7. swift 实现websocket与后台通信(swift 如何构建简单的json字符串)

    一个应用不可避免要与服务器进行通信,主要有,http与socket。http暂时不论,我们先看看socket下面衍生的websocket,今天我就把自己怎么利用websocket与服务器进行交互记录下来:首先你需要集成websocket到自己的项目,如果不明白如何集成,请看上一篇《swift集成websocket库》集成websocket到自己项目后还需要添加SwiftyJSON到自己项目,具体步骤和集成websocket一样。首先打开你项目,记得通过cocoapods生成的.xcworkspace文件打

  8. 如何在Android上托管REST webservices?

    有没有人知道一个用Java编写的能够在Android上托管REST服务的开源Web服务器?

  9. android – WebSocket没有关闭重装应用程序(React Native)

    附:哦,我用Android进行测试.解决方法你的代码看起来不错.通过刷新你的意思是在调试模式下运行时刷新javascript?

  10. android – 移动设备上的WebSocket支持

    对于Android多人游戏的玩家之间的通信,我正在使用WebSocket服务器和客户端的TooTallNate’sJavalibrary,以在Android应用程序中启用WebSocket支持.所以只是要明确指出,移动浏览器中的WebSocket支持对我来说并不重要.不幸的是,用户报告说他们遇到了连接失败或未接收消息等问题.这是移动设备上WebSockets的一般问题,还是客户端代码中的一个缺陷?您是否具有WebSocket客户端库的经验,例如上面的那个?WebSocket技术不是完全正确的解决方案,因此

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部