Java - WebSocket

一、WebSocket

1.1、WebSocket概念

WebSocket是一种协议,用于在Web应用程序和服务器之间建立实时、双向的通信连接。它通过一个单一的TCP连接提供了持久化连接,这使得Web应用程序可以更加实时地传递数据。WebSocket协议最初由W3C开发,并于2011年成为标准。

1.2、WebSocket协议

WebSocket 协议是一种基于TCP的协议,用于在客户端和服务器之间建立持久连接,并且可以在这个连接上实时地交换数据。WebSocket协议有自己的握手协议,用于建立连接,也有自己的数据传输格式。

当客户端发送一个 WebSocket 请求时,服务器将发送一个协议响应以确认请求。在握手期间,客户端和服务器将协商使用的协议版本、支持的子协议、支持的扩展选项等。一旦握手完成,连接将保持打开状态,客户端和服务器就可以在连接上实时地传递数据。

WebSocket 协议使用的是双向数据传输,即客户端和服务器都可以在任意时间向对方发送数据,而不需要等待对方的请求。它支持二进制数据和文本数据,可以自由地在它们之间进行转换。

总之,WebSocket协议是一种可靠的、高效的、双向的、持久的通信协议,它适用于需要实时通信的Web应用程序,如在线游戏、实时聊天等

1.3、WebSocket原理

WebSocket 生命周期描述了 WebSocket 连接从创建到关闭的过程。一个 WebSocket 连接包含以下四个主要阶段:

  • 连接建立阶段(Connection Establishment):在这个阶段,客户端和服务器之间的 WebSocket 连接被建立。客户端发送一个 WebSocket 握手请求,服务器响应一个握手响应,然后连接就被建立了。
  • 连接开放阶段(Connection Open):在这个阶段,WebSocket 连接已经建立并开放,客户端和服务器可以在连接上互相发送数据。
  • 连接关闭阶段(Connection Closing):在这个阶段,一个 WebSocket 连接即将被关闭。它可以被客户端或服务器发起,通过发送一个关闭帧来关闭连接。
  • 连接关闭完成阶段(Connection Closed):在这个阶段,WebSocket 连接已经完全关闭。客户端和服务器之间的任何交互都将无效

客户端依靠发起HTTP握手,告诉服务端进行WebSocket协议通讯,并告知WebSocket协议版本。服务端确认协议版本,升级为WebSocket协议。之后如果有数据需要推送,会主动推送给客户端

请求头Request Headers

GET /test HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: sehfiowqweuq1psd==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp, v12.stomp
Origin: http://hello.com
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Version: 13

首先客户端(如浏览器)发出带有特殊消息头(Upgrade、Connection)的请求到服务器,服务器判断是否支持升级,支持则返回响应状态码101,表示协议升级成功,对于WebSocket就是握手成功。其中关键的字段就是Upgrade,Connection,告诉 Apache 、 Nginx 等服务器:注意啦,发起的是Websocket协议,不再 使用原先的HTTP。其中,Sec-WebSocket-Key当成是请求id就好了。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HaA6EjhHRejpHyuO0yBnY4J4n3A=
Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15
Sec-WebSocket-Protocol: v12.stomp

Sec-WebSocket-Accept的字段值是由握手请求中的Sec-WebSocket-Key的字段值生成的。成功握手确立WebSocket连接之后,通信时不再使用HTTP的数据帧,而采用WebSocket独立的数据帧

1.4、 应用场景

实时聊天:聊天应用需要实时的消息传递,WebSocket 提供了高效的解决方案。

在线游戏:游戏中的实时交互(例如玩家动作和状态更新)可以通过 WebSocket 高效地处理。

股票市场:股票和金融市场应用需要实时更新数据,WebSocket 能够提供实时行情和交易信息。

实时通知:例如社交网络应用中的即时通知和更新。

协作应用:如实时文档编辑和在线协作工具,可以使用 WebSocket 实现多用户之间的同步更新。

WebSocket 协议在许多现代网络应用中扮演了重要角色,特别是在需要高频率数据交换和低延迟响应的场景中

1.5、WebSocket优劣势

WebSocket优势:

  • 实时性:由于WebSocket的持久化连接,它可以实现实时的数据传输,避免了Web应用程序需要不断地发送请求以获取最新数据的情况。
  • 双向通信:WebSocket协议支持双向通信,这意味着服务器可以主动向客户端发送数据,而不需要客户端发送请求。
  • 减少网络负载:由于WebSocket的持久化连接,它可以减少HTTP请求的数量,从而减少了网络负载。

WebSocket劣势:

  • 需要浏览器和服务器都支持:WebSocket是一种相对新的技术,需要浏览器和服务器都支持。一些旧的浏览器和服务器可能不支持WebSocket。
  • 需要额外的开销:WebSocket需要在服务器上维护长时间的连接,这需要额外的开销,包括内存和CPU。
  • 安全问题:由于WebSocket允许服务器主动向客户端发送数据,可能会存在安全问题。服务器必须保证只向合法的客户端发送数据

1.6、http和websocket区别

(1)WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息;HTTP是单向的

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

二、Java中使用WebSocket

2.1、Java WebSocket API编写WebSocket

2.1.1、WebSocket服务器的搭建方法

在Java中搭建WebSocket服务器的方法如下:

1、首先,需要引入Java WebSocket API库。可以从Maven仓库下载Java WebSocket API依赖,或者直接将相关jar文件添加到项目中。

2、创建一个WebSocket服务器类,实现javax.websocket.Endpoint接口。这个类将作为WebSocket服务器的入口点,并定义了处理WebSocket连接和消息的方法。

3、在服务器类中,重写以下方法:

@OnOpen:注解用于标记一个方法,当WebSocket与客户端成功建立连接时,这个方法将被调用。

@OnMessage:注解标记的方法会在收到客户端发送的消息时被调用。在示例中,收到消息后会打印消息内容,并将响应消息发送回客户端。

@OnClose:注解标记的方法会在WebSocket关闭时被调用。

@OnError:注解标记的方法会在发生错误时被调用。

在类上使用@ServerEndpoint注解,将这个类声明为一个WebSocket端点。/websocket是WebSocket的URI,客户端可以通过这个URI来连接到这个WebSocket端点。

4、使用javax.websocket.server.ServerEndpoint注解标记服务器类,指定WebSocket的URL路径。

5、创建一个WebSocket服务器容器类,用来启动和管理WebSocket服务器。可以使用javax.websocket.server.ServerEndpointConfig的Builder类创建一个服务器配置对象,将服务器类和URL路径关联起来,并配置其他相关信息。

6、使用WebSocket服务器容器类的create方法创建一个WebSocket服务器实例。

7、启动WebSocket服务器,可以使用Server.start()方法

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
 
@ServerEndpoint("/websocket")
public class WebSocketServer {
 
    @OnOpen
    public void onOpen(Session session) {
        // 在连接打开时执行的操作
    }
 
    @OnClose
    public void onClose(Session session) {
        // 在连接关闭时执行的操作
    }
 
    @OnMessage
    public void onMessage(String message, Session session) {
        // 处理收到的消息
    }
}

编写配置类

// 需要注入Bean的话必须声明为配置类
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

 调用:

import javax.websocket.server.ServerEndpointConfig;
 
public class WebSocketServerContainer {
 
    public static void main(String[] args) {
        ServerEndpointConfig serverConfig = ServerEndpointConfig.Builder.create(WebSocketServer.class, "/websocket").build();
        WebSocketContainer container = ContainerProvider.getWebSocketContainer();
        try {
            container.connectToServer(serverConfig, new URI("ws://localhost:8080/"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

:这里监听的地址不可以是 "ws" 不然会报错,可能这是关键字吧,毕竟我们的协议就叫 ws 

2.1.2、Vue + JS 实现客户端

<template>
  <div class="app-container home">
    <el-row :gutter="20">
      <el-col :sm="24" :lg="24">
        <h1>集成websocket测试</h1>
      </el-col>
    </el-row>
    <el-row :gutter="20">
      <el-col :sm="24" :lg="24">
        <div>
          <el-input v-model="url" type="text" style="width: 20%" /> &nbsp;
          &nbsp;
          <el-button @click="join" type="primary">连接</el-button>
          <el-button @click="exit" type="danger">断开</el-button>
          <el-button @click="resetForm" type="success">重置</el-button>
          <br />
          <br />
          <el-input type="textarea" v-model="message" :rows="9" />
          <br />
          <br />
          <el-button type="success" @click="send">发送消息</el-button>
          <br />
          <br />
          返回内容
          <el-input type="textarea" v-model="text_content" :rows="9" />
          <br />
          <br />
        </div>
      </el-col>
    </el-row>
  </div>
</template>
 
 
<script>
import { getToken } from "@/utils/auth";
 
export default {
  name: "Index",
  data() {
    return {
      url: "ws://127.0.0.1:8080/websocket/message",
      message: "",
      text_content: "",
      ws: null,
      headers: {
        Authorization: "Bearer " + getToken(),
      },
    };
  },
  methods: {
    join() {
      const wsuri = this.url;
      // this.ws = new WebSocket(wsuri);
      this.ws = new WebSocket(wsuri, [getToken()]);
      const self = this;
      // 连接成功后调用
      this.ws.onopen = function (event) {
        self.text_content = self.text_content + "WebSocket连接成功!" + "\n";
      };
      this.ws.onerror = function (event) {
        self.text_content = self.text_content + "WebSocket连接发生错误!" + "\n";
      };
      // 接收后端消息
      this.ws.onmessage = function (event) {
        self.text_content = self.text_content + event.data + "\n";
      };
      // 关闭连接时调用
      this.ws.onclose = function (event) {
        self.text_content = self.text_content + "已经关闭连接!" + "\n";
      };
    },
    exit() {
      if (this.ws) {
        this.ws.close();
        this.ws = null;
      }
    },
    send() {
      if (this.ws) {
        this.ws.send(this.message);
      } else {
        alert("未连接到服务器");
      }
    },
    //重置
    resetForm() {
      this.message = "";
      this.text_content = "";
    },
  },
};
</script>

2.2、Spring Boot集成WebSocket

2.2.1、添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

2.2.2、配置WebSocket

应用程序中,需要配置WebSocket。创建一个新的Java类,并添加注。@ServerEndpoint(“/websocket”)。这将指定WebSocket服务端的端点。

在此类中,需要实现几个方法:

import javax.websocket.OnClose;

import javax.websocket.OnMessage;

import javax.websocket.OnOpen;

import javax.websocket.Session;

import javax.websocket.server.ServerEndpoint;

  

@ServerEndpoint("/websocket")
public class WebSocketServer {
    @OnOpen
    public void onOpen(Session session) {
        System.out.println("Connection opened: " + session.getId());
        sessions.add(session);
    }

    @OnMessage
    public void onMessage(Session session, String message) throws IOException {
        System.out.println("Received message: " + message);
        session.getBasicRemote().sendText("Server received: " + message);
    }
  
    @OnClose
    public void onClose(Session session) {
        System.out.println("Connection closed: " + session.getId());
        sessions.remove(session);
    }

    private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>());
}

2.2.3、处理WebSocket消息

在@OnMessage方法中,可以处理WebSocket客户端发送的消息,并向客户端发送响应。下面是一个简单的示例代码:

@OnMessage
public void onMessage(Session session, String message) throws IOException {
    System.out.println("Received message: " + message);
    session.getBasicRemote().sendText("Server received: " + message);
}

在此代码中,我们简单地打印出收到的消息,并向客户端发送响应。

关闭WebSocket连接

在@OnClose方法中,可以删除连接并做一些清理工作。下面是一个示例代码:

@OnClose
public void onClose(Session session) {
    System.out.println("Connection closed: " + session.getId());
    sessions.remove(session);
}

在此代码中,我们从连接池中删除连接,并打印出连接已关闭的消息。

配置WebSocket支持

最后,需要配置Spring Boot以支持WebSocket。创建一个新的Java类,并添加注释@Configuration和@EnableWebSocket。然后,需要覆盖方法registerWebSocketHandlers(),并指定WebSocket处理程序。下面是一个示例代码:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new WebSocketServer(), "/websocket").setAllowedOrigins("*");
    }
}

在此代码中,我们创建了一个新的WebSocketServer对象,并将其添加到WebSocket处理程序中。我们还指定了WebSocket端点(/websocket)和允许的来源(*)。

三、PostMan调用

3.1、Websocket在线模拟请求工具

访问访问地址:http://www.jsons.cn/websocket/

具有进行连接、断开、模拟发送数据等功能。

(请求时注意连接格式为 ws://IP或域名:端口(示例 ws://127.0.0.1:8089/websocket/devices)

3.2、Postman

使用新版的Postman

1、建立 WebSocket 连接

在 File–> New 页面,选择 WebSocket Request,即可创建一个 WebSocket 模拟请求。

2、模拟数据交互

在地址栏中输入相应的 WebSocket 请求地址,点击地址栏右侧的 “Connect” 按钮,即可建立连接。

连接建立成功后,在 Message 的信息栏中输入模拟数据,点击 “Send” 按钮,即可与服务端进行数据交互。

优势:

支持多种数据格式

如:Text、JSON、XML、HTML、Binary等;

支持对交互信息进行格式化显示

如:Text、JSON、XML、HTML等;

支持对交互数据进行模糊搜索、筛选过滤、清空等操作;

交互数据按照时间倒序显示,更便于查看最新的数据。

3、断开 WebSocket 连接

如果调试结束,点击地址栏右侧的 “Disconnect” 按钮,即可断开与 WebSocket 服务端的连接

可参考

WebSocket详解及使用教程:打造高效的实时通信(二)_利用websocket进行聊天-CSDN博客


Java中使用WebSocket的几种方式_java_脚本之家

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/891366.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【CSS】houdini自定义CSS属性实现渐变色旋转动画

现有一段代码&#xff0c;在不旋转整个元素的前提下&#xff0c;渐变背景无法应用动画 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initia…

专业模拟训练头显,Varjo XR-4 如何开启虚拟仿真新模拟时代

虚拟仿真模拟训练是提升技能熟练度与工作安全性的有效解决方案&#xff0c;Varjo XR-4作为专业模拟训练头显&#xff0c;凭借其出色的技术特性和性能&#xff0c;正在引领虚拟仿真模拟训练进入一个全新的时代。 一、卓越的视觉体验 高分辨率显示器&#xff1a;Varjo XR-4配备…

计算机毕业设计 基于Python的美术馆预约系统的设计与实现 Python毕业设计 Python毕业设计选题【附源码+安装调试】

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

三子棋(C 语言)

目录 一、游戏设计的整体思路二、各个步骤的代码实现1. 菜单及循环选择的实现2. 棋盘的初始化和显示3. 轮流下棋及结果判断实现4. 结果判断实现 三、所有代码四、总结 一、游戏设计的整体思路 &#xff08;1&#xff09;提供一个菜单让玩家选择人机对战、玩家对战或者退出游戏…

大厂面试真题-组合和聚合的区别是什么

组合和聚合比较类似&#xff0c;二者都表示整体和部分之间的关系。 聚合关系的特点是&#xff1a;整体由部分构成&#xff0c;但是整体和部分之间并不是强依赖的关系&#xff0c;而是弱依 赖的关系&#xff0c;也就是说&#xff0c;即使整体不存在了&#xff0c;部分仍然存在…

Zabbix监控vCenter虚拟机

1. vcenter上配置snmp agent 如果配置 vCenter Server Appliance SNMP 代理以用于轮询,则它可以侦听和响应来自 SNMP 管理客户端系统的请求,如 GET、GETNEXT 和 GETBULK 请求. 使用root身份进入vcenter命令行,开启snmp代理 Command> snmp.enable Command> snmp.set…

正则表达式 | Python、Julia 和 Shell 语法详解

正则表达式在网页爬虫、脚本编写等众多任务中都有重要的应用。为了系统梳理其语法&#xff0c;以及 Python、Julia 和 Shell 中与正则表达式相关的工具&#xff0c;本篇将进行详细介绍。 相关学习资源&#xff1a;编程胶囊。 基础语法 通用语法 在大多数支持正则表达式的语…

24/10/14 视觉笔记 图像拼接融合

图像拼接分为四步 1.特征点提取 2.特征点匹配 3.仿射矩阵计算 4.图像拼接与融合 1.特征提取 找到图像中具有显著性信息点&#xff0c;并计算该点的特征表达 def detectAndDescrible(img):#构建STFT特征检测器sift cv2.SIFT_create()#特征提取kps,features sift.detectA…

3-3 AUTOSAR RTE 对SR Port的实现

返回总目录->返回总目录<- 目录 一、前言 二、显式访问 三、隐式访问 四、队列调用(Queued) 五、无效数据元素 一、前言 RTE作为SWC和BSW之间的通信机构,支持Sender-Receiver方式实现ECU内及ECU间的通信。 对于Sender-Receiver Port支持三种模式: 显式访问:若…

京东零售数据湖应用与实践

作者&#xff1a;陈洪健&#xff1a;京东零售大数据架构师&#xff0c;深耕大数据 10 年&#xff0c;2019 年加入京东&#xff0c;主要负责 OLAP 优化、大数据传输工具生态、流批一体、SRE 建设。 当前企业数据处理广泛采用 Lambda 架构。Lambda 架构的优点是保证了数据的完整性…

LeetCode|70.爬楼梯

这道题很像斐波那契数列&#xff0c;但是初始值不同&#xff0c;也有动态规划的解法&#xff0c;但是一开始我想到的是递归写法。现在我们站在第n阶台阶&#xff0c;那么&#xff0c;我们上一步就有两种可能&#xff1a;1、我们从第n-1阶台阶走一步上来的&#xff1b;2、我们从…

弹出“xinput1_3.dll文件缺失”的错误要怎么处理?一键修复xinput1_3.dll

当你尝试打开游戏或应用时&#xff0c;如果弹出“xinput1_3.dll文件缺失”的错误&#xff0c;请记得及时处理。这个文件是DirectX中用于处理游戏控制器输入的关键组件。这个问题可以通过几个简单的步骤轻松解决。本指南将教你如何快速恢复或替换丢失的xinput1_3.dll文件&#x…

免费Excel工作表同类数据合并工具

下载地址&#xff1a;https://pan.quark.cn/s/81b1aeb45e4c 在 Excel 表格里&#xff0c;当我们试图手动将多行同类数据合并为一行时&#xff0c;会遭遇诸多棘手的困难以及繁杂的操作流程。在确定哪些数据属于可合并的同类数据时&#xff0c;单纯依靠人工进行对比&#xff0c;极…

SQL数据库刷题sql_day33(连续3次为球队得分的球员名单)

描述 两支篮球队进行了激烈的比赛&#xff0c;比分交替上升。比赛结束后&#xff0c;你有一个两队分数的明细表&#xff08;名称为“分数表”&#xff09;。 表中记录了球队、球员号码、球员姓名、得分分数及得分时间。现在球队要对比赛中表现突出的球员进行奖励。 问题&#x…

用最短长度的绳子把整个花园围起来

给定一个数组 trees&#xff0c;其中 trees[i] [xi, yi] 表示树在花园中的位置。 你被要求用最短长度的绳子把整个花园围起来&#xff0c;因为绳子很贵。只有把 所有的树都围起来&#xff0c;花园才围得很好。 返回恰好位于围栏周边的树木的坐标。 示例 1: 输入: points […

MySQL 的数据类型

1.整数类型 1.1 tinyint tinyint 为小整数类型&#xff0c;存储空间为1个字节&#xff08;8位&#xff09;&#xff0c;有符号范围-128 ~ 127&#xff0c;无符号范围 0 ~ 255,此类型通常在数据库中表示类型的字段&#xff0c;如某一字段 type 表示学科,其中 “type1” 表示语文…

实战篇:(二)React 创建项目并连接 MySQL 后台的实战教程

React 创建项目并连接 MySQL 后台的实战教程 一、项目概述 本篇博客将介绍如何使用 React 搭建前端项目&#xff0c;并通过 Node.js 和 MySQL 实现简单的后台数据连接。通过这个项目&#xff0c;你将掌握从前端到后端数据库的基础开发流程&#xff0c;适合初学者或正在项目实…

中国各大一线及二线省会城市程序员收入大比拼,看看你所在的城市的统计是否准确

在中国&#xff0c;程序员的收入因城市、经验、学历等因素而有所不同。本文将对一线及二线省会城市的程序员收入进行详细比较&#xff0c;帮助大家了解各地的薪资水平。 一线城市程序员收入 上海 上海作为中国的经济中心&#xff0c;程序员收入最高。根据最新数据&#xff…

新生编程入门的方式探讨

关于如何编程入门&#xff0c;这是一个很好的问题。在上大学之前&#xff0c;并没有怎么接触电脑的我&#xff0c;也许可以谈一谈。 还记得在高中的时候&#xff0c;因为很多同学去网吧玩电脑打游戏&#xff0c;被学校开除&#xff0c;老师谆谆教诲大家不要去网吧&#xff0c;所…

Word粘贴时出现“文件未找到:MathPage.WLL”的解决方案

解决方案 一、首先确定自己电脑的位数&#xff08;这里默认大家的电脑都是64位&#xff09;二、右击MathType桌面图标&#xff0c;点击“打开文件所在位置”&#xff0c;然后分别找到MathPage.WLL三、把这个文件复制到该目录下&#xff1a;C:\Program Files\Microsoft Office\r…