Java - WebSocket

news2024/11/26 20:42:45

一、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_脚本之家

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3种常用的缓存读写策略详解

在详解3种常用的缓存读写之前&#xff0c;我们先要了解什么事缓存读写。 缓存读写是指在使用缓存技术时&#xff0c;对数据进行读取和更新的操作过程。缓存是一种用于提高系统性能和可扩展性的技术&#xff0c;通过减少对慢速存储&#xff08;如数据库&#xff09;的访问次数&…

CAN总线仲裁机制

文章目录 1、什么是CAN总线仲裁&#xff1f;2、仲裁机制3、仲裁过程 1、什么是CAN总线仲裁&#xff1f; CAN总线上的每个节点都能监测到总线上发送的数据&#xff0c;当总线空闲时每个节点都能够进行报文发送&#xff0c;多个节点同时发送报文时&#xff0c;最终由哪个节点来进…

中间件有哪些分类?

中间件的分类 中间件是位于操作系统和应用程序之间的软件&#xff0c;它提供了一系列服务来简化分布式系统中的应用程序开发和集成。中间件可以根据其功能和用途被分为不同的类别。以下是中间件的一些主要分类&#xff1a; 1. 通信处理&#xff08;消息&#xff09;中间件&am…

Sentinel 1.80(CVE-2021-44139)

Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;主要以流量为切入点&#xff0c;从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性 Report a Sentinel Security Vulnerability …

华为eNSP实验:以太网交换---MAC地址漂移防止与检测

一&#xff1a;MAC地址漂移 MAC地址漂移是一种网络攻击技术&#xff0c;它利用了网络设备&#xff08;如交换机&#xff09;的动态学习特性来改变网络流量的路径。这种攻击可能导致数据包被错误地转发到未经授权的设备上&#xff0c;从而造成信息泄露或拒绝服务攻击。为了防止…

ViirtualBox+Vagrant快速创建虚拟机,固定IP地址

ViirtualBoxVagrant配置虚拟机共分三步 1.ViirtualBox的安装 2.Vagrant的安装 3.VirtualBoxVagrant配置虚拟机 1.安装virtual Box 2.进入官网 下载 https://www.virtualbox.org/wiki/Downloads 下载对应版本 https://www.virtualbox.org/wiki/Download_Old_Builds_6_1 使用…

物联网中的远距离通信LoRa无线技术

LoRa&#xff08;Long Range Radio&#xff09;远距离无线传输技术是基于扩频调制技术的低功耗、远距离无线通信技术&#xff0c;采用扩频调制&#xff0c;通过将原始信号与一个伪随机序列进行编码&#xff0c;使得信号的带宽显著增加&#xff0c;从而在更宽的频谱上传输。这种…

《征服数据结构》并查集(DSU)

摘要&#xff1a; 1&#xff0c;并查集的介绍 2&#xff0c;并查集的查找 3&#xff0c;并查集的合并 1&#xff0c;并查集的介绍 并查集(Disjoint-set data structure&#xff0c;不交集数据结构)是用于处理一些不交集的合并以及查询问题&#xff0c;它是非常重要的一种数据结…

在 Qt 中实现可拖动的无边框 MainWindow 并设置圆角效果

在应用程序的界面设计中,很多时候我们希望窗口能够拥有更好的视觉效果,比如设置圆角以及去除默认的标题栏,使窗口看起来更加美观。此外,还需要支持用户通过鼠标拖动窗口。在本文中,我们将详细介绍如何在 Qt 中实现这些效果。 如图: 一、设置无边框窗口 Qt 提供了 Qt::F…

风格迁移-StyTr 2 : Image Style Transfer with Transformers

风格迁移-StyTr 2 : Image Style Transfer with Transformers 论文链接&#xff1a;Image Style Transfer with Transformers 源码链接&#xff1a;StyTR-2 文章目录 风格迁移-StyTr 2 : Image Style Transfer with TransformersStyTR架构图图像内容编码器内容感知位置编码&…

libaom 源码分析系列:svc_encoder_rtc.cc 文件

源码函数关系 文件功能:实现 AV1 svc 编码的 RTC 功能 demo文件位置:libaom/examples/svc_encoder_rtc.cc文件内函数关系图: 结构体 AppInput:svc_encoder_rtc.cc 所属 demo 的结构体,作为从命令行接受参数的结构体;AvxVideoWriter:输出视频写入结构体;aom_codec_enc_c…

服务器部署‌Traefik 实现子级域名路由服务(对外子域名80,路由对内大端口)

文章目录 1.‌Traefik安装2.启动nginx配置路由 本文档只是为了留档方便以后工作运维&#xff0c;或者给同事分享文档内容比较简陋命令也不是特别全&#xff0c;不适合小白观看&#xff0c;如有不懂可以私信&#xff0c;上班期间都是在得 前言&#xff0c;领导让我调研在线发布得…

Cocos Creator 原生Android项目打 aab 包,升级到Android14(API 34)

注意:打aab包的前提是需要配置对应gradle文件。这里我简单说下,我这边做的。 1.setting.gradle文件中配置 include ‘:asset_pack’ 。如下图 2.找到对应的 asset_pack 的 gradle文件,一定要改assetPack。如下图: deliveryType = “install-time” //PAD资源分发 安装时分…

LiveGBS流媒体平台GB/T28181常见问题-视频服务器有多个IP多个网段的时候如何配置摄像头下级平台接入多网段收流?

LiveGBS常见问题视频服务器有多个IP多个网段的时候如何配置摄像头下级平台接入多网段收流&#xff1f; 1、背景2、查看设备的出口IP3、默认收流地址配置4、其它网络设备收流配置5、搭建GB28181视频直播平台 1、背景 服务器部署的时候&#xff0c;可能有多个网卡多个网段。Live…

常见webshell后门查杀工具

文章目录 D盾百度webshell在线查杀河马webshellkiller长亭牧云微步在线云沙箱Web Shell DetectorVirusTotal D盾 D盾Webshell后门查杀工具由阿D开发&#xff0c;是一款免费且功能强大的Webshell查杀软件。它利用自行研发的代码分析引擎&#xff0c;能够高效、准确地检测并清除…

Ubuntu QT 交叉编译环境搭建

文章目录 下载安装qtCreatornot a valid identifier 的错误 安装g下载并安装交叉编译器下载交叉编译器安装交叉编译器 下载编译 ARM 的Qt平台源码配置arm的QT平台 下载安装qtCreator 去QT下载官网下载对应需要的QT软件。 这里下载5.12.96版本的 改变安装包权限&#xff0c;…

k8s芜湖

一、k8s简介及部署方法 1、k8s简介 kubernetes的本质是一组服务器集群&#xff0c;它可以在集群的每个节点上运行特定的程序&#xff0c;来对节点中的容器进行管理。目的是实现资源管理的自动化&#xff0c;主要提供了如下的主要功能&#xff1a; 自我修复&#xff1a;一旦某一…

DBO-BP回归预测 | MATLAB实现DBO-BP蜣螂优化算法优化神经网络多输入单输出回归预测

回归预测 | MATLAB实现DBO-BP蜣螂优化算法优化神经网络多输入单输出回归预测 目录 回归预测 | MATLAB实现DBO-BP蜣螂优化算法优化神经网络多输入单输出回归预测基本介绍程序设计参考资料基本介绍 MATLAB实现DBO-BP蜣螂优化算法优化神经网络多输入单输出回归预测。 蜣螂优化群优…

react理念(二)

react-fiber 虚拟dom在react16中称为fiber。 起源 在react15之前&#xff0c;协调器采用递归的方式来创建dom&#xff0c;递归的过程是不能中断的&#xff0c;如果组件书的层级很深&#xff0c;递归会占用线程很多时间&#xff0c;造成卡顿。为了解决这个问题&#xff0c;re…

统一流程引擎如何具体实现对多系统业务流程的整合?

在信息化时代&#xff0c;企业和组织通常会使用多个业务系统来满足不同的业务需求。然而&#xff0c;这些分散的业务系统往往会导致业务流程的碎片化&#xff0c;降低工作效率。统一流程引擎的出现为解决这一问题提供了有效的途径。它能够整合多系统的业务流程&#xff0c;实现…