websocket入门及应用

news2024/12/30 3:54:19

websocket

When to use a HTTP call instead of a WebSocket (or HTTP 2.0)

WebSocket 是基于TCP/IP协议,独立于HTTP协议的通信协议。WebSocket 是双向通讯,有状态,客户端一(多)个与服务端一(多)双向实时响应(客户端 ⇄ 服务端)。WebSocket 是应用在浏览器的 Socket (是 Socket 模型接口的实现),Socket 是一个网络通信接口 (通信规范)。

WebSocket协议端口是80。WebSocket SSL协议端口是443。*Socket是TCP/IP协议的网络数据通讯接口(一种底层的通讯的方式)。image-20230827173621392

image-20230827180052083

引入依赖

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

定义配置类

@Configuration
public class WebsocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

定义controller

定义controller接口规范传输

public interface WebsocketHandler {

    void onOpen(Session session);
    void onClose(Session session);
    void onMessage(String message);
}

定义controller实现交互

package com.wnhz.wnmap.schedule.controller;

import com.wnhz.wnmap.schedule.vo.MessageVo;
import com.wnhz.wnmap.schedule.common.util.JsonUtil;
import com.wnhz.wnmap.schedule.handler.WebsocketHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Objects;


@ServerEndpoint("/ws/api")
@Slf4j
public class ScheduleController implements WebsocketHandler {

    private Session session;
    private int count;


    @OnOpen
    @Override
    public void onOpen(Session session) {
        this.session = session;
        MessageVo webMessage = new MessageVo(++count, MessageVo.MessageType.WEBSOCKET_OPEN, "websocket连接成功...");
        String message = JsonUtil.toString(webMessage);
        this.sendMessage(message);
        log.debug("websocket建立成功.......");
    }

    @OnClose
    @Override
    public void onClose(Session session) {
        this.session = session;
        MessageVo webMessage = new MessageVo(--count, MessageVo.MessageType.WEBSOCKET_OPEN, "websocket断开连接成功...");
        String message = JsonUtil.toString(webMessage);
        this.sendMessage(message);
        log.debug("websocket关闭成功.......");
    }

    @OnMessage
    @Override
    public void onMessage(String message) {
        MessageVo messageVo = new MessageVo();
        messageVo.setType(MessageVo.MessageType.WEBSOCKET_MESSAGE);  //类型3指信息交互
        messageVo.setCount(count);
        messageVo.setMessage(message);

        String json = JsonUtil.toString(messageVo);
        this.sendMessage(json);
        log.debug("[websocket消息:]收到客户端发来的消息:{}", message);
    }

    private void sendMessage(String message) {
        try {
            log.debug("[websocket服务器返回信息:] {}", message);
            if(Objects.nonNull(this.session)){
                this.session.getBasicRemote().sendText(message);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

vue+wesocket

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Websocket</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>

<div id="app">
    <textarea>{{msg}}</textarea>
    <hr/>
    <input type="text" placeholder="请输入传输数据" v-model="sendTxt">
    <button @click="wsend">发送</button>

</div>

<script>
    new Vue({
        el: '#app',
        data() {
            return {
                websocket: null,
                msg: '',
                sendTxt: ''
            }
        },
        created() {
            this.init();
        },
        methods: {
            init: function () {
                this.websocket = new WebSocket('ws://localhost:15555/ws/api');
                this.websocket.onopen = this.wopen;
                this.websocket.onmessage = this.wMessage;
                this.websocket.onclose = this.wclose;
            },
            wopen: function () {
                console.log("socket连接成功.....")
            },
            wMessage: function (e) {
                console.log("接收到的信息: " + e.data )
                let data = eval("(" + e.data + ")"); //解析对象
                this.msg = data.message;
            },
            wclose: function () {
                console.log("websocket连接端口.....")
            },
            wsend: function () {
                console.log("发送新消息......" + this.sendTxt);
                this.websocket.send(this.sendTxt);
            }
        },
        destroyed() {
            this.websocket.onclose = this.close();
        }

    });

</script>

</body>
</html>

image-20230827212823339

前后端交互案例

案例一

后端
public interface WebSocketHandler {
    void onOpen(Session session);
    void onClose();
    void onMessage(String message);
}

public class WebSocketServer implements WebsocketHandler {



    @OnOpen
    @Override
    public void onOpen(Session session) {
        System.out.println("连接--->"+session);

        WebSocketUtil.put(session);
        log.debug("前端与后台建立连接:{}", this);
    }

    @OnClose
    @Override
    public void close() {
        log.debug("前端已关闭连接:{}", this);
        //webSocketServers.remove(this);
    }

    @OnMessage
    @Override
    public void onMessage(String message) {
        log.debug("接收到前端信息:{}", message);
        log.debug("---------向前端发送信息-----------------");
        //  sendMessage("[服务器:] 你好,信息从后台返回");
    }




    @RabbitListener(queues = "regist_simple_queue")
    public void registryUser(User user) throws Exception {
        System.out.println("消费--->"+user);
        //System.out.println("------------>"+WebSocketUtil.get());
        Thread.sleep(5000);
        WebSocketUtil.get().getBasicRemote().sendText(user.getUsername()+"已经注册成功^_^");


    }
}
package com.wnhz.vue.web.socket;

import javax.websocket.Session;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;

public class WebSocketUtil {
    private static final CopyOnWriteArrayList<Session> sessions = new CopyOnWriteArrayList<>();

    public static void put(Session session){
       sessions.add(session);
    }

    public static int size(){
       return sessions.size();
    }

    public static Session get(){
        return sessions.get(0);
    }
}

前端
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <title>vue发送websocket-to springboot</title>
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>

</head>
<body>

<div id="app">
    <input type="text" v-model="book.title" placeholder="书名">
    <input type="text" v-model="book.author" placeholder="作者">
    <input type="text" v-model="book.price" placeholder="价格">
    <input type="text" v-model="book.category" placeholder="类别">
    <button >运行 WebSocket</button>
</div>

<script>
    new Vue({
        el: '#app',
        data() {
            return {
                book: {
                    title: '',
                    author: '',
                    price: '',
                    category: ''
                },
                websocketPath: 'ws://localhost:9090/mysocket',
                ws: null
            }
        },
        mounted() {
            this.ws = new WebSocket(this.websocketPath);
            this.ws.onopen = this.open;
            this.ws.onmessage = this.getMessage;
            this.ws.onclose = this.close;
        },
        methods: {
            open: function () {
                this.ws.send("发送数据");
                console.log("websocket连接成功...");
            },

            getMessage: function (event) {
                let received_msg = event.data;
                console.log("receive: "+ received_msg);
                this.$message({
                    message: received_msg,
                    type: 'success'
                });
            },
            close: function () {
                console.log("websocket连接已经关闭")
            }
        },
        destroyed() {
            this.ws.onclose = this.close();
        }
    });
</script>

</body>
</html>

案例二

前端
<template>
    <div>
        <el-input v-model="msg" placeholder="请问您还有什么问题?"></el-input>
        <el-button type="button" @click="wssend">发送给客服</el-button>
    </div>
</template>

<script>
export default {
    data() {
        return {
            websocket: null,
            msg: ''
        };
    },
    created() {
        this.websocket = new WebSocket('ws://localhost:9999/mysocket');
        this.websocket.onopen = this.wsopen;
        this.websocket.onclose = this.wsclose;
        this.websocket.onmessage = this.wsmessage;
    },
    methods: {
        wsopen() {
            console.log("websocket连接成功.....")
        },
        wsclose() {
            console.log("websocket关闭成功.....")
        },
        wsmessage(event) {
            //获取后台交互
            console.log("===>" + event.data);
                this.$notify({
                    title: '来自客服',
                    message: event.data,
                    duration: 2000
                });      
        },
        wssend() {
            this.websocket.send(this.msg);
        }
    }
}
</script>
后台
package com.wnhz.websocket.ws;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;

@Component
@ServerEndpoint("/mysocket")
@Slf4j
public class WebSocketController {
    /**
     * 建立websocket连接
     */
    @OnOpen
    public void onOpen(Session session) throws IOException {
        log.debug("建立websocket连接成功,sessionId:{}",session.getId());
        session.getBasicRemote().sendText("[from server:]"+"I'm fine!!!");

    }

    @OnClose
    public void onClose(Session session) throws IOException {
        log.debug("websocket连接断开,sessionId:{}",session.getId());
        session.close();
    }

    @OnMessage
    public void sendMessage(Session session,String message) throws IOException {
        log.debug("[from web:]{}",message);
        if("你好".equals(message)){
            session.getBasicRemote().sendText("亲,您好,有什么能为您服务的^_^");
        }
        if("退货".equals(message)){
            session.getBasicRemote().sendText("对不起,客服繁忙中,请稍后再咨询");
        }
    }
}

应用场景

1.社交订阅

对社交类的应用的一个裨益之处就是能够即时的知道你的朋友正在做什么。虽然听起来有点可怕,但是我们都喜欢这样做。你不会想要在数分钟之后才能知道一个家庭成员在馅饼制作大赛获胜或者一个朋友订婚的消息。你是在线的,所以你的订阅的更新应该是实时的。

2.多玩家游戏

网络正在迅速转变为游戏平台。在不使用插件(我指的是Flash)的情况下,网络开发者现在可以在浏览器中实现和体验高性能的游戏。无论你是在处理DOM元素、CSS动画,HTML5的canvas或者尝试使用WebGL,玩家之间的互动效率是至关重要的。我不想在我扣动扳机之后,我的对手却已经移动位置。

3.协同编辑/编程

我们生活在分布式开发团队的时代。平时使用一个文档的副本就满足工作需求了,但是你最终需要有一个方式来合并所有的编辑副本。版本控制系统,比如Git能够帮助处理某些文件,但是当Git发现一个它不能解决的冲突时,你仍然需要去跟踪人们的修改历史。通过一个协同解决方案,比如WebSocket,我们能够工作在同一个文档,从而省去所有的合并版本。这样会很容易看出谁在编辑什么或者你在和谁同时在修改文档的同一部分。

4.点击流数据

分析用户与你网站的互动是提升你的网站的关键。HTTP的开销让我们只能优先考虑和收集最重要的数据部分。然后,经过六个月的线下分析,我们意识到我们应该收集一个不同的判断标准——一个看起来不是那么重要但是现在却影响了一个关键的决定。与HTTP请求的开销方式相比,使用Websocket,你可以由客户端发送不受限制的数据。想要在除页面加载之外跟踪鼠标的移动?只需要通过WebSocket连接发送这些数据到服务器,并存储在你喜欢的NoSQL数据库中就可以了(MongoDB是适合记录这样的事件的)。现在你可以通过回放用户在页面的动作来清楚的知道发生了什么。

5.股票基金报价

金融界瞬息万变——几乎是每毫秒都在变化。我们人类的大脑不能持续以那样的速度处理那么多的数据,所以我们写了一些算法来帮我们处理这些事情。虽然你不一定是在处理高频的交易,但是,过时的信息也只能导致损失。当你有一个显示盘来跟踪你感兴趣的公司时,你肯定想要随时知道他们的价值,而不是10秒前的数据。使用WebSocket可以流式更新这些数据变化而不需要等待。

6.体育实况更新

现在我们开始讨论一个让人们激情澎湃的愚蠢的东西——体育。我不是运动爱好者,但是我知道运动迷们想要什么。当爱国者在打比赛的时候,我的妹夫将会沉浸于这场比赛中而不能自拔。那是一种疯狂痴迷的状态,完全发自内心的。我虽然不理解这个,但是我敬佩他们与运动之间的这种强烈的联系,所以,最后我能做的就是给他的体验中降低延迟。如果你在你的网站应用中包含了体育新闻,WebSocket能够助力你的用户获得实时的更新。

7.多媒体聊天

视频会议并不能代替和真人相见,但当你不能在同一个屋子里见到你谈话的对象时,视频会议是个不错的选择。尽管视频会议私有化做的“不错”,但其使用还是很繁琐。我可是开放式网络的粉丝,所以用WebSockets getUserMedia API和HTML5音视频元素明显是个不错的选择。WebRTC的出现顺理成章的成为我刚才概括的组合体,它看起来很有希望,但其缺乏目前浏览器的支持,所以就取消了它成为候选人的资格。

8.基于位置的应用

越来越多的开发者借用移动设备的GPS功能来实现他们基于位置的网络应用。如果你一直记录用户的位置(比如运行应用来记录运动轨迹),你可以收集到更加细致化的数据。如果你想实时的更新网络数据仪表盘(可以说是一个监视运动员的教练),HTTP协议显得有些笨拙。借用WebSocket TCP链接可以让数据飞起来。

9.在线教育

上学花费越来越贵了,但互联网变得更快和更便宜。在线教育是学习的不错方式,尤其是你可以和老师以及其他同学一起交流。很自然,WebSockets是个不错的选择,可以多媒体聊天、文字聊天以及其它优势如与别人合作一起在公共数字黑板上画画…

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

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

相关文章

7.(数据结构)堆

7.1 相关概念 堆&#xff08;Heap&#xff09;在计算机科学中是一种特殊的数据结构&#xff0c;它通常被实现为一个可以看作完全二叉树的数组对象。以下是一些关于堆的基本概念&#xff1a; 数据结构&#xff1a; 堆是一个优先队列的抽象数据类型实现&#xff0c;通过完全二叉树…

Oracle 基础表管理(Heap-Organized Table Management)

表是数据库中负责数据存储的对象&#xff0c;在RDBMS中&#xff0c;数据以行、列的形式存储在表中。Oracle中表有很多种类型&#xff0c;最基础且应用最常用的类型就是堆表&#xff08;Heap-Organized Table&#xff09;&#xff0c;本文列举了Oracle堆表的常用管理操作。 一、…

【PX4-AutoPilot教程-仿真环境架构】梳理PX4GazeboMAVLinkMAVROSROSROS2之间的关系

梳理PX4&Gazebo&MAVLink&MAVROS&ROS&ROS2之间的关系 PX4与仿真器PX4支持的仿真器PX4与除Gazebo之外的仿真器的连接PX4与Gazebo仿真器的连接 PX4默认的MAVLink UDP端口PX4 SITL软件在环仿真的架构Gazebo仿真PX4启动仿真的launch文件ROS与PX4的关系 PX4与仿真…

LeetCode 0938.二叉搜索树的范围和:深度优先搜索(可中序遍历)

【LetMeFly】938.二叉搜索树的范围和&#xff1a;深度优先搜索&#xff08;可中序遍历&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/range-sum-of-bst/ 给定二叉搜索树的根结点 root&#xff0c;返回值位于范围 [low, high] 之间的所有结点的值的和。…

《武汉市贯彻实施细则》解读房地产经纪活动时效性

时效性【当前有效】 为进一步规范我市房地产经纪活动&#xff0c;保护房地产交易和经纪活动当事人的合法权益&#xff0c;促进行业健康发展&#xff0c;制定《武汉市房地产经纪实施细则》&#xff08;以下简称《实施细则》&#xff09;。 &#xff08;以下简称《实施细则》&am…

《Docker 简易速速上手小册》第5章 Docker Compose 与服务编排(2024 最新版)

文章目录 5.1 理解 Docker Compose5.1.1 重点基础知识5.1.2 重点案例&#xff1a;部署 Flask 应用和 Redis5.1.3 拓展案例 1&#xff1a;多服务协作5.1.4 拓展案例 2&#xff1a;使用自定义网络 5.2 编排多容器应用5.2.1 重点基础知识5.2.2 重点案例&#xff1a;部署 Flask 应用…

OpenCV开发笔记(七十五):相机标定矫正中使用remap重映射进行畸变矫正

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://blog.csdn.net/qq21497936/article/details/136293833 各位读者&#xff0c;知识无穷而人力有穷&#xff0c;要么改需求&#xff0c;要么找专业人士&#xff0c;要么自己研究 红胖子(红模仿…

用html编写的简易新闻页面

用html编写的简易新闻页面 相关代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document<…

信号完整性分析基本概念

“设计师可以分成两类&#xff0c;一类已经遇到了信号完整性问题&#xff0c;另一类即将遇到信号完不整性问题” 随着时钟频率的提高&#xff0c;发现并解决信号完整性问题成为产品开发的关键。因此需要精通信号完整性分析技术&#xff0c;并能采取高效设计过程以消除这些问题…

内网穿透的应用-如何在群晖配置WebDAV实现云同步Zotero科研文献与笔记【内网穿透】

文章目录 前言1. Docker 部署 Trfɪk2. 本地访问traefik测试3. Linux 安装cpolar4. 配置Traefik公网访问地址5. 公网远程访问Traefik6. 固定Traefik公网地址 前言 Trfɪk 是一个云原生的新型的 HTTP 反向代理、负载均衡软件&#xff0c;能轻易的部署微服务。它支持多种后端 (D…

Sentinel 动态规则扩展

一、规则 Sentinel 的理念是开发者只需要关注资源的定义&#xff0c;当资源定义成功后可以动态增加各种流控降级规则。Sentinel 提供两种方式修改规则&#xff1a; 通过 API 直接修改 (loadRules)通过 DataSource 适配不同数据源修改 手动通过 API 修改比较直观&#xff0c;…

linux下执行文件包含^M,将window文件格式内容转为linux格式

查看文件内容 cat -v jvm_options 报错信息 ./bin/install-plugin.sh: /bigdata/opt/s/seatunnelsgg/apache-seatunnel-2.3.4/mvnw: /bin/sh^M: bad interpreter: No such file or directory install connector : connector-selectdb-cloud安装工具 yum install -y dos2uni…

Linux——静态库

Linux——静态库 静态库分析一下 ar指令生成静态库静态库的使用第三方库优化一下 gcc -I(大写的i) -L -l(小写的l)&#xff0c;头文件搜索路径&#xff0c;库文件搜索路径&#xff0c;连接库 今天我们来学习静态库的基本知识。 静态库 在了解静态库之前&#xff0c;我们首先来…

YOLOv9中的RepNCSPELAN4结构!

RepNCSPELAN4结构出炉啦&#xff0c;收藏起来写论文用&#xff01; 1.代码&#xff1a; 代码路径&#xff1a;yolov9-main->models->common.py&#xff0c;代码如下&#xff1a; class RepNCSPELAN4(nn.Module):# csp-elandef __init__(self, c1, c2, c3, c4, c51): # …

哪些行业适合做小程序?零售电商、餐饮娱乐、旅游酒店、教育生活、医疗保健、金融社交、体育健身、房产汽车、企管等,你的行业在其中么?

引言 在当今数字化时代&#xff0c;小程序成为了各行各业快速发展的数字工具之一。它的轻便、灵活的特性使得小程序在多个行业中找到了广泛的应用。本文将探讨哪些行业适合开发小程序&#xff0c;并介绍各行业中小程序的具体应用。 一、零售和电商 在当今数字化的商业环境中&…

聊聊 Go 边界检查消除

前言 在这篇文章中碰巧看到了Go边界检查消除相关的讨论. 我也借此简单聊聊. 有这样一段代码, 非常简单, 就是一段求向量点积的程序: func sum(a, b []int) int {if len(a) ! len(b) {panic("must be same len")}ret : 0for i : 0; i < len(a); i {ret a[i] * …

tab 切换页面

<template><divclass"syncData"v-loading"fullscreenLoading"element-loading-spinner"el-icon-loading"element-loading-background"rgba(0, 0, 0, 0.8)"element-loading-text"拼命加载中"><el-tabsv-model…

【c语言】字符函数和字符串函数(下)

前言 书接上回 【c语言】字符函数和字符串函数(上) 上一篇讲解的strcpy、strcat、strcmp函数的字符串长度是不受限制的 而本篇strncpy、strncat、strcnmp函数的字符串长度是受限制的 欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;…

C/C++有序数组中插入元素

一、不利用指针 代码&#xff1a; int i; void insert(int ,int , int ); int main() {int a[100];int n, m;cout<<"输入数组元素个数\n";cin >> n;cout << "输入数组元素\n";for (i 0; i < n; i) {cin >> a[i];}cout <&…

C语言里面的内存函数

1.memcpy函数 &#xff08;1&#xff09;函数的模拟实现&#xff0c;这个函数的作用就是把arr1拷贝到arr2里面&#xff0c;单位是字节&#xff0c;20字节就是5整 数&#xff0c;所以输出的就是1234500000&#xff1b; &#xff08;2&#xff09;之所以强制类型转换成为char*是…