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);
        }
    }
相关推荐
憨子周1 小时前
2M的带宽怎么怎么设置tcp滑动窗口以及连接池
java·网络·网络协议·tcp/ip
霖雨2 小时前
使用Visual Studio Code 快速新建Net项目
java·ide·windows·vscode·编辑器
SRY122404192 小时前
javaSE面试题
java·开发语言·面试
Fiercezm3 小时前
JUC学习
java
无尽的大道3 小时前
Java 泛型详解:参数化类型的强大之处
java·开发语言
ZIM学编程3 小时前
Java基础Day-Sixteen
java·开发语言·windows
我不是星海3 小时前
1.集合体系补充(1)
java·数据结构
P.H. Infinity3 小时前
【RabbitMQ】07-业务幂等处理
java·rabbitmq·java-rabbitmq
爱吃土豆的程序员3 小时前
java XMLStreamConstants.CDATA 无法识别 <![CDATA[]]>
xml·java·cdata
2401_857610034 小时前
多维视角下的知识管理:Spring Boot应用
java·spring boot·后端