java网络通信:Springboot整合Websocket

news2024/12/27 13:06:52

网络通信

  • 什么是webSocket?
  • WebSocket 原理
  • springboot整合websocket过程

网络通信三要素:ip地址(ipv4、ipv6)、端口号(应用程序的唯一标识)、协议(连接和通信的规则,常用:tcp、udp)

小区-房屋-道路
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Socket 是 “套接字” 的缩写,它用于在计算机之间建立通信链接,允许数据在这些连接上进行传输。

什么是webSocket?

WebSocket(Web套接字)是一种在单个 TCP 连接上实现全双工通信的协议,允许客户端和服务器之间进行双向实时通信。WebSocket 是 HTML5 标准的一部分,其主要特点包括:

  1. 双向通信: WebSocket 允许服务器向客户端主动推送消息,同时也允许客户端发送消息给服务器,实现了双向通信。
  2. 持久连接: 与传统的 HTTP 请求-响应模型不同,WebSocket 连接在建立后可以一直保持,而不需要为每个消息都建立新的连接,减少了通信的延迟和开销。
  3. 低延迟: WebSocket 具有较低的通信延迟,适用于需要实时性的应用,如在线聊天、实时数据监控、在线游戏等。
  4. 跨域支持: WebSocket 支持跨域通信,可以在不同域名的服务器之间建立连接。
  5. 轻量级头部: WebSocket 协议的头部数据较小,减少了通信开销。

WebSocket 原理

WebSocket 协议建立在 HTTP 协议之上,通过 HTTP 请求的升级机制(Upgrade)来升级为 WebSocket 连接。基本的连接过程如下:
客户端发起 WebSocket 连接请求,与服务器建立 TCP 连接

服务器响应 WebSocket 握手请求,双方达成协议升级,完成连接建立。

建立连接后,客户端和服务器可以通过 WebSocket 消息进行双向通信。

连接可以一直保持开启,直到其中一方发送关闭连接请求。

WebSocket 连接是一个持久连接,使用固定的套接字地址(ws:// 或 wss://)和端口号(通常是 80 或 443)。WebSocket 消息使用一种轻量级的帧格式,减少了通信开销。这使得 WebSocket 适用于需要实时通信的应用,如在线聊天、实时数据更新、在线游戏等。

在 Java 中,WebSocket 库通常会处理 WebSocket 握手、消息编码和解码、连接管理等底层细节,开发者可以专注于应用层的逻辑。WebSocket 协议的双向通信模型使其成为实时通信应用的理想选择,它在实时性要求高的场景中有广泛的应用。

springboot整合websocket过程

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version> <!-- 使用正确的版本号 -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>springws</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springws</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>8</java.version>
    </properties>

基本依赖

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

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
            <version>5.3.12</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-websocket</artifactId>
            <version>9.0.55</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

</project>

系统配置

server.port=8080
# WebSocket
websocket.address=ws://localhost:8080

配置文件

@Configuration
public class WebSocketConfig {

    @Value("${ws://localhost:8080}")
    private String websocketAddress;

    /**
     * 注入ServerEndpointExporter,
     * 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

Wbsocket操作类

在这里插入图片描述

package com.hs.websocket;

import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
@Slf4j
@ServerEndpoint("/websocket/{userId}")  // 接口路径 ws://localhost:8087/webSocket/userId;
public class WebSocket {

    private Session session;
    private String userId;
    private static Map<String, Session> sessionPool = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        this.session = session;
        this.userId = userId;
        sessionPool.put(userId, session);
        log.info("&#8203;``【oaicite:3】``&#8203;有新的连接,总数为: {}", sessionPool.size());
    }

    @OnClose
    public void onClose() {
        sessionPool.remove(userId);
        log.info("&#8203;``【oaicite:2】``&#8203;连接断开,总数为: {}", sessionPool.size());
    }

    @OnMessage
    public void onMessage(String messageText) {
        log.info("&#8203;``【oaicite:1】``&#8203;收到客户端消息: {}", messageText);
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("用户错误, 原因: {}", error.getMessage());
    }

    public void sendAllMessage(String message) {
        log.info("&#8203;``【oaicite:0】``&#8203;广播消息: {}", message);
        sessionPool.values().forEach(this::sendMessage);
    }

    public void sendOneMessage(String targetUserId, String message) {
        Session session = sessionPool.get(targetUserId);
        if (session != null && session.isOpen()) {
            sendMessage(session, message);
        }
    }

    public void sendMoreMessage(String[] targetUserIds, String message) {
        for (String targetUserId : targetUserIds) {
            Session session = sessionPool.get(targetUserId);
            if (session != null && session.isOpen()) {
                sendMessage(session, message);
            }
        }
    }

    private void sendMessage(Session targetSession, String message) {
        try {
            targetSession.getAsyncRemote().sendText(message);
        } catch (IOException e) {
            log.error("发送消息失败: {}", e.getMessage());
        }
    }
}

前端测试

<!DOCTYPE HTML>
<html>
<head>
    <title>Test My WebSocket</title>
</head>


<body>
TestWebSocket
<input id="text" type="text"/>
<button onclick="send()">SEND MESSAGE</button>
<button onclick="closeWebSocket()">CLOSE</button>
<div id="message"></div>
</body>

<script type="text/javascript">
    var websocket = null;


    //判断当前浏览器是否支持WebSocket
    if ('WebSocket' in window) {
        //连接WebSocket节点
        websocket = new WebSocket("ws://localhost:8080/websocket/88");
    } else {
        alert('Not support websocket')
    }


    //连接发生错误的回调方法
    websocket.onerror = function () {
        setMessageInnerHTML("error");
    };


    //连接成功建立的回调方法
    websocket.onopen = function (event) {
        setMessageInnerHTML("open");
    }


    //接收到消息的回调方法
    websocket.onmessage = function (event) {
        setMessageInnerHTML(event.data);
    }


    //连接关闭的回调方法
    websocket.onclose = function () {
        setMessageInnerHTML("close");
    }


    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function () {
        websocket.close();
    }


    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML) {
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }


    //关闭连接
    function closeWebSocket() {
        websocket.close();
    }


    //发送消息
    function send() {
        var message = document.getElementById('text').value;
        websocket.send(message);
    }
</script>
</html>

postman测试

创建新的workspaces

通过ctrl+n进入
在这里插入图片描述

基于以下url进行联通测试

ws://localhost:8080/websocket/88

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

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

相关文章

9 网关的作用

1、总结&#xff1a; 1.如果离开本局域网&#xff0c;就需要经过网关&#xff0c;网关是路由器的一个网口。 2.路由器是一个三层设备&#xff0c;里面有如何寻找下一跳的规则 3.经过路由器之后 MAC 头要变&#xff0c;如果 IP 不变&#xff0c;相当于不换护照的欧洲旅游&#…

Android:Type io.reactivex.android.R is defined multiple times

项目直接运行没有问题&#xff0c;但是打正式包会报这个错误&#xff0c; 错误的重点是io.reactivex.android.R这个引用的包与项目中引用的包冲突&#xff0c; 需要改成相同的版本 即可

Java中对象的比较:复写基类的equals+Comparble接口类的比较+比较器比较+PriorityQueue的比较+源码分析

文章目录 Java中对象的比较一、元素的比较二、对象的比较1.复写基类的equals2.基于Comparble接口类的比较3.基于比较器比较三种方法的对比 4. 集合框架中PriorityQueue的比较方式 Java中对象的比较 一、元素的比较 在Java中&#xff0c;基本类型的对象可以直接比较大小。 二、…

哪款手机便签软件支持存储录音文件并支持转文字?

手机便签类软件带有存储录音转文字功能是比较实用的&#xff0c;很多人通常会整理很多录音类型的文件&#xff0c;录音文件整合在一起后&#xff0c;后续有需要可以逐条点开播放收听。尤其是在工作中&#xff0c;当领导说一些重点时&#xff0c;大家无法借助灵活的大脑来成功的…

第20章_Myisam与InnoDB

文章目录 区别如何选择innodb额外补充知识innodb为什么推荐使用自增ID作为主键innodb引擎4大特性 区别 InnoDB支持事务&#xff0c;MyISAM不支持&#xff0c;对于InnoDB每一条SQL语言都默认封装成事务&#xff0c;自动提交&#xff0c;这样会影响速度&#xff0c;所以最好把多条…

编写MBR主引导记录

BIOS 检测&#xff0c;初始化硬件。挑一些重要的&#xff0c;能保证计算机能运行那些硬件的基本IO操作。 唤醒BIOS 唤醒BIOS需要知道其入口地址&#xff0c;在最后将跳转到0x7c00处 接电的一瞬间&#xff0c;cs:ip寄存器被初始化为0xF000:0xFFF0&#xff0c;所以等效地址是0…

Mybatis-Plus前后端分离多表联查模糊查询分页

数据准备 数据库配置: /*Navicat Premium Data TransferSource Server : localhost_3306Source Server Type : MySQLSource Server Version : 80100 (8.1.0)Source Host : localhost:3306Source Schema : test01Target Server Type : MySQLT…

Ubuntu20.0工作区(workspace)介绍,切换工作区方式和快捷键

Ubuntu20.0工作区&#xff08;workspace&#xff09;介绍&#xff0c;切换工作区方式和快捷键 先修改一下ubuntu截屏的快捷键查看工作区新建工作区工作区切换 先修改一下ubuntu截屏的快捷键 修改为 查看工作区 按下Super键&#xff08;即Windows键&#xff09;&#xff0c;可…

sql学习笔记(三)

目录 1.四舍五入 2.向上取整 3.向下取整 4.Hive 分区 5.case when条件语句 6.日期函数 7.字符串函数 8.窗口函数 1️⃣排序函数 1.四舍五入 round select round(3.14) —>3 2.向上取整 ceiling select ceiling(12.15) —>13 3.向下取整 floor select flo…

【网络协议】

网络协议 1 网络通讯1.1 防火墙1.2 子网掩码1.3 网关1.4 2 SSH2.1 SSH2.2 SSH12.3 SSH2 3 Telnet4 Telnet/SSL5 NFS6 TFTP7 FTP8 SFTP9 HTTP10 HTTPS11 NAT12 加密 1 网络通讯 1.1 防火墙 所谓“防火墙”&#xff0c;是指一种将内部网和公众访问网(如Internet)分开的方法&…

spring中纯注解实现Advice

背景&#xff1a;课本上是注解和Xml文件混用的方式&#xff0c;研究了一下用配置类加注解和测试方法实现各种通知方式的切入。 1.首先dao的接口&#xff0c;增删改查 public interface UserDaoAspect {public void add();public void delete();public void update();public vo…

【K-means聚类算法】实现鸢尾花聚类

文章目录 前言一、数据集介绍二、使用步骤1.导包1.2加载数据集1.3绘制二维数据分布图1.4实例化K-means类&#xff0c;并且定义训练函数1.5训练1.6可视化展示2.聚类算法2.1.可视化生成3其他聚类算法进行鸢尾花分类 前言 例如&#xff1a;随着人工智能的不断发展&#xff0c;机器…

Vue 3 相对于 Vue2,模板和组件的一些变化

目录 1&#xff0c;模板的变化1&#xff0c;v-modelvue2vue3 2&#xff0c;v-if 和 v-for3&#xff0c;keyv-forv-if 4&#xff0c;Fragment 2&#xff0c;组件的变化1&#xff0c;Teleport2&#xff0c;异步组件 1&#xff0c;模板的变化 1&#xff0c;v-model vue2 对组件…

c语言初学者用vs还是vscode?

c语言初学者用vs还是vscode? 看是科班还是自学&#xff0c;一般学校会有要求的编译软件&#xff0c;在这两者之间&#xff0c;用VS的居多&#xff0c;一个可能的原因是VS不用自己装环境。 最近很多小伙伴找我&#xff0c;说想要一些 c语言的资料&#xff0c;然后我根据自己从…

Rust核心功能之一(所有权)

目录 1、什么是所有权&#xff1f; 1.1 所有权规则 1.2 变量作用域 1.3 String 类型 1.4 内存与分配 变量与数据交互的方式&#xff08;一&#xff09;&#xff1a;移动 变量与数据交互的方式&#xff08;二&#xff09;&#xff1a;克隆 只在栈上的数据&#xff1a;拷贝…

【C++20】模块

模块 C语言从一开始便继承了C语言的include头文件机制&#xff0c;通过包含头文件的方式来引用其他组件的代码&#xff0c;这些头文件通常包含了该组件相关的接口声明。但使用头文件通常伴有如下问题&#xff1a; 不够清晰不够清晰同名符号覆盖问题 C20提供了模块特性&#…

本地生活新赛道-视频号团购怎么做?

目前有在做实体行业的商家一定要看完&#xff0c;只要你进入了这个本地生活新的赛道&#xff0c;那你的生意自然会源源不断&#xff0c;那这个赛道又是什么呢&#xff1f; 这就是十月份刚刚上线的视频号团购项目&#xff0c;开通团购之后&#xff0c;就可以通过发短视频&#…

排序:堆排序(未完待续)

文章目录 排序一、 排序的概念1.排序&#xff1a;2.稳定性&#xff1a;3.内部排序&#xff1a;4.外部排序&#xff1a; 二、插入排序1.直接插入排序 二、插入排序堆排序 排序 一、 排序的概念 1.排序&#xff1a; 一组数据按递增/递减排序 2.稳定性&#xff1a; 待排序的序列…

postman中文乱码

在header中添加这两个&#xff1a; Content-Type application/json;charsetUTF-8 Accept application/json;charsetUTF-8

『昆仑天工』4款AI产品开源!提供API对接!

在文章开篇&#xff0c;小圈先介绍下 昆仑万维 公司旗下的AI大模型**『天工』**&#xff0c;它是由昆仑万维自研的双千亿级大语言模型&#xff0c; 也是国内首个对标ChatGPT的双千亿级大语言模型&#xff0c;可满足文案创作、知识问答、代码编程、逻辑推演、数理推算等需求。 …