websocket

websocket

  • websocket概述
  • websocket入门
  • springboot整合Websocket

websocket概述

1 为什么需要websocket?

​ 我们在上网时经常会遇到一些情况,就是页面没有刷新,但是一些数据会发生了改变,比如:在邮箱页面当收到新邮件时,我们并没有刷新页面,但是却会主动提示有新邮件达到,并会将未读邮件的数量+1。或者是在一些购物网站,当有新消息时并没有刷新页面,却提示了我们有新消息未读。

​ 那像这样的业务场景是怎么实现的呢?为什么页面没有刷新,浏览器却提醒我们有新消息呢?

​ 解决方案:

1、采用轮询的方式。即:通过js不断的请求服务器,查看是否有新数据,如果有,就获取到新数据。这种解决方法是否存在问题呢?

​ 当然是有的,如果服务端一直没有新的数据,那么js也是需要一直的轮询查询数据,这就是一种资源的浪费。

2、使用webSocket来解决

那什么是websocket呢?

2 什么是WebSocket?

​ WebSocket是一种网络通信协议,它允许在单个TCP连接上进行全双工通信。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。

​ WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就可以直接创建持久性的连接,并进行双向数据传输。这种技术通过HTTP/1.1协议的101状态码进行握手,实现了一种长连接,使得双方可以实时地进行信息交换。

全双工(Full Duplex)、半双工(Half Duplex)和单工(Simplex Communication)是数据通信中描述数据在线路上传输方向的不同方式。

  1. 全双工(Full Duplex): 全双工允许数据在两个方向上同时传输,即通信的双方可以同时发送和接收数据。这相当于两个单工通信方式的结合,数据在两个方向上可以同时流动。全双工通信在发送数据的同时也能够接收数据,两者同步进行。例如,我们平时打电话时,可以同时说话并听到对方的声音,这就是全双工通信的一个典型例子。
  2. 半双工(Half Duplex): 半双工通信是指数据可以沿两个方向传送,但同一时刻一个信道只允许单方向传送,因此又被称为双向交替通信。在半双工通信中,虽然数据可以在两个方向上传输,但在任何时刻只能由其中的一方发送数据,另一方接收数据。若要改变传输方向,需由开关进行切换。例如,无线对讲机就是一种半双工设备,在同一时间内只允许一方讲话。
  3. 单工(Simplex Communication): 单工通信模式的数据传输是单向的。通信双方中,一方固定为发送端,一方则固定为接收端。信息只能沿一个方向传输,使用一根传输线。移动通信按照用户的通话状态和频率使用的方法,可分为单工制、半双工制和双工制。例如,计算机与打印机之间的通信是单工模式,因为只有计算机向打印机传输数据,而没有相反方向的数据传输。

总结来说,全双工、半双工和单工是数据通信中描述数据在线路上传输方向的不同方式。全双工允许数据在两个方向上同时传输,半双工允许数据在两个方向上交替传输,而单工则只允许数据在一个方向上传输。

WebSocket具有以下特点:

  1. 双向通信:WebSocket协议支持客户端和服务器之间的双向通信,使得双方可以实时地进行信息交换。
  2. 实时性:WebSocket协议的设计目标就是提供实时的通信体验,因此它能够有效地减少延迟,提高通信效率。
  3. 持久连接:WebSocket协议使用TCP的持久连接,这意味着一旦建立了连接,服务器就可以主动推送信息给客户端,而不需要每次都进行握手和建立连接的过程。
  4. 兼容性:WebSocket协议具有良好的兼容性,它可以在不同的设备和浏览器上使用,包括移动设备和PC浏览器。
  5. 事件驱动:WebSocket协议是基于事件驱动的,这意味着它能够更好地处理异步操作和实时事件。

WebSocket的应用场景包括但不限于实时聊天、股票交易、实时地图等需要实时数据传输的应用。它相对于传统的轮询和Comet技术,能够更节省服务器资源和带宽,并且能够更实时地进行通讯。

3 http和webSocket的区别

http协议是短连接,因为请求之后,都会关闭连接,下次重新请求数据,需要再次打开链接。

WebSocket协议是一种长链接,只需要通过一次请求来初始化链接,然后所有的请求和响应都是通过这个TCP链接进行通讯。

总结:

1、http和websocket的相同点

​ 都是一样基于TCP的,都是可靠性传输协议。

​ 都是应用层协议。

2、 http和WebSocket的区别

​ WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息。HTTP是单向的。

​ WebSocket是需要浏览器和服务器握手进行建立连接的。而http是浏览器发起向服务器的连接,服务器预先并不知道这个连接。

联系

​ WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协议的。

4 浏览器对于webSocket的支持情况

​ 目前,基本上所有的主流浏览器都支持WebSocket。具体来说,Chrome从Chrome 4开始支持WebSocket,Firefox从Firefox 4开始支持,Safari从Safari 5开始支持,而Edge也支持WebSocket。这些浏览器都内置了对WebSocket协议的实现,使得开发者可以在网页中轻松地使用WebSocket进行实时通信。

网址: https://caniuse.com/?search=websocket

三 webSocket入门

1 websocket的相关注解说明

  • @ServerEndpoint("/websocket/{uid}")这个注解是写在类上面的申明这是一个websocket服务需要指定访问该服务的地址,在地址中可以指定参数,需要通过{}进行占位

  • @OnOpen用法:public void onOpen(Session session, @PathParam("uid") String uid) throws IOException{}该方法将在建立连接后执行,会传入session对象,就是客户端与服务端建立的长连接通道通过@PathParam获取url传递中的参数

  • @OnClose用法:public void onClose() {}该方法是在连接关闭后执行

  • @OnMessage用法:public void onMessage(String message, Session session) throws IOException {}该方法用于接收客户端发来的消息message:发来的消息数据session:会话对象(也是通道)

  • 发送消息到客户端用法:session.getBasicRemote().sendText("你好");通过session进行发送。

2 入门实现

创建一个Web项目

导包

复制代码
<dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-api</artifactId>
      <version>7.0</version>
      <scope>provided</scope>
    </dependency>

编写webSocket入门代码

复制代码
package cn.ronghuanet;


import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/websocket/{uid}")
public class MyWebSocket {

    @OnOpen
    public void onOpen(Session session, @PathParam("uid")String uid)throws Exception{
        session.getBasicRemote().sendText(uid+"欢迎你!成功连接到websocket");
    }

    @OnClose
    public void onClose(){
        System.out.println("关闭连接");
    }

    @OnMessage
    public void onMessage(String message,Session session)throws Exception{
        System.out.println("接收到消息"+message);
        session.getBasicRemote().sendText("你好,我已收到你的消息");
    }

    @OnError
    public void onError(Session session,Throwable throwable){
        System.out.println("出错了!!!!!");
        throwable.printStackTrace();
    }
}

写前端页面用来做测试

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script type="text/javascript">
    const socket = new WebSocket("ws://localhost:8080/websocket/1");
    socket.onopen = (ws) =>{
        console.log("建立连接!", ws);
    }
    socket.onmessage = (ws) =>{
        console.log("接收到消息 >> ",ws.data);
    }
    socket.onclose = (ws) =>{
        console.log("连接已断开!", ws);
    }
    socket.onerror = (ws) => {
        console.log("发送错误!", ws);
    }
    // 2秒后向服务端发送消息
    setTimeout(()=>{
        socket.send("发送一条消息试试");
    },2000);
    // 5秒后断开连接
    setTimeout(()=>{
        socket.close();
    },5000);
</script>
</body>
</html>

将项目部署到tomcat,访问页面测试

3 springboot整合WebScoekt

3.1 基本实现

创建新项目

导入依赖

复制代码
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
    </parent>
        <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
</dependencies>

启动类

复制代码
@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

}

消息处理类,在spring中,处理消息的具体业务逻辑需要实现WebSocketHandler接口

复制代码
/**
 * 在本类中接收前端传递的消息,进行处理
 */
@Component
public class MyHandler extends TextWebSocketHandler {

    /**
     * 处理文本消息
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        System.out.println("接收到前端传递的消息-->"+payload);
        session.sendMessage(new TextMessage("===你好,我已经收到你的消息了======="));

        if(message.getPayload().equals("10")){
            for (int i = 0; i < 10; i++) {
                session.sendMessage(new TextMessage("返回第"+i+"条消息到前端"));
                Thread.sleep(1000);
            }
        }
    }

    /**
     * 建立连接之后
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("uid==>"+session.getAttributes().get("uid"));
        System.out.println("欢迎你连接到websocket服务啊");
    }

    /**
     * 断开连接之后
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        System.out.println("连接已经被关闭了..............");
    }
}

websocket配置类,在该类中配置handler的访问path以及允许访问的源等

复制代码
/**
 * 注册websocket的处理类
 */
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Autowired
    private MyHandler myHandler;


    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myHandler, "ws").setAllowedOrigins("*");
    }
}

编写前端用于测试

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>websocket测试页面</title>
</head>
<body>
    <script type="text/javascript">
        const socket = new WebSocket("ws://localhost:8080/ws");
        socket.onopen = (ws) =>{
            console.log("和后端建立连接==>", ws);
        }
        socket.onmessage = (ws) =>{
            console.log("接收到后端返回来的消息==> ",ws.data);
        }
        socket.onclose = (ws) =>{
            console.log("连接已断开!", ws);
        }
        socket.onerror = (ws) => {
            console.log("发送错误!", ws);
        }
        // 2秒后向服务端发送消息
        setTimeout(()=>{
            socket.send("10");
        },5000);
        window.setInterval(() => {
            socket.send("后端你好,我是前端");
        },1000)
        // 5秒后断开连接
        /*setTimeout(()=>{
            socket.close();
        },5000);*/
    </script>
</body>
</html>

启动项目,在浏览器访问前端页面用于测试

3.2 webSocket拦截器

在Spring中提供了websocket拦截器,可以在建立连接之前写些业务逻辑,比如校验登录等。

复制代码
@Component
public class MyHandleSnakeInterceptor implements HandshakeInterceptor {

    /**
     * 握手前
     * @param request
     * @param response
     * @param wsHandler
     * @param attributes
     * @return  true 建立连接   false 不满足条件,不建立连接
     * @throws Exception
     */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
                                   WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
        System.out.println("准备握手了");
        attributes.put("uid", 10001);
        return true;
    }

    /**
     * 握手后
     * @param request
     * @param response
     * @param wsHandler
     * @param exception
     */
    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
        System.out.println("握手成功了!!!!!!!");
    }
}

在配置类中配置该拦截器要作用于哪些Handler

java 复制代码
 /**
     * 注册websocket的处理类
     */
    @Configuration
    @EnableWebSocket
    public class WebSocketConfig implements WebSocketConfigurer {
    
        @Autowired
        private MyHandler myHandler;
    
        @Autowired
        private MyHandleSnakeInterceptor myHandleSnakeInterceptor;
    
        @Override
        public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
            registry.addHandler(myHandler, "ws").setAllowedOrigins("*")
                    .addInterceptors(myHandleSnakeInterceptor);
        }
    }
相关推荐
杨DaB14 分钟前
【SpringBoot】Swagger 接口工具
java·spring boot·后端·restful·swagger
YA33315 分钟前
java基础(九)sql基础及索引
java·开发语言·sql
桦说编程34 分钟前
方法一定要有返回值 \ o /
java·后端·函数式编程
小李是个程序1 小时前
登录与登录校验:Web安全核心解析
java·spring·web安全·jwt·cookie
David爱编程1 小时前
Java 创建线程的4种姿势,哪种才是企业级项目的最佳实践?
java·后端
hrrrrb2 小时前
【Java Web 快速入门】十一、Spring Boot 原理
java·前端·spring boot
Java微观世界2 小时前
Object核心类深度剖析
java·后端
MrSYJ2 小时前
为什么HttpSecurity会初始化创建两次
java·后端·程序员
hinotoyk2 小时前
TimeUnit源码分享
java
AAA修煤气灶刘哥3 小时前
Java+AI 驱动的体检报告智能解析:从 PDF 提取到数据落地全指南
java·人工智能·后端