websokcet服务端实现

一/websokcet服务端实现

步骤一: springboot底层帮我们自动配置了websokcet,引入maven依赖

1

2

3

4

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-websocket</artifactId>

</dependency>

步骤二:如果是你采用springboot内置容器启动项目的,则需要配置一个Bean。如果是采用外部的容器,则可以不需要配置。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

/**

 * @Description: 配置类

 */

@Component

public class WebSocketConfig {

  

    /**

     * ServerEndpointExporter 作用

     *

     * 这个Bean会自动注册使用@ServerEndpoint注解声明的websocket endpoint

     *

     * @return

     */

    @Bean

    public ServerEndpointExporter serverEndpointExporter() {

        return new ServerEndpointExporter();

    }

}

 步骤三:最后一步当然是编写服务端核心代码了,其实本人不是特别想贴代码出来,贴很多代码影响文章可读性。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

package com.example.socket.code;

  

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.PathParam;

import javax.websocket.server.ServerEndpoint;

import java.util.concurrent.ConcurrentHashMap;

  

/**

 * @Description: websocket 服务类

 */

  

/**

 *

 * @ServerEndpoint 这个注解有什么作用?

 *

 * 这个注解用于标识作用在类上,它的主要功能是把当前类标识成一个WebSocket的服务端

 * 注解的值用户客户端连接访问的URL地址

 *

 */

  

@Slf4j

@Component

@ServerEndpoint("/websocket/{name}")

public class WebSocket {

  

    /**

     *  与某个客户端的连接对话,需要通过它来给客户端发送消息

     */

    private Session session;

  

     /**

     * 标识当前连接客户端的用户名

     */

    private String name;

  

    /**

     *  用于存所有的连接服务的客户端,这个对象存储是安全的

     */

    private static ConcurrentHashMap<String,WebSocket> webSocketSet = new ConcurrentHashMap<>();

  

  

    @OnOpen

    public void OnOpen(Session session, @PathParam(value = "name") String name){

        this.session = session;

        this.name = name;

        // name是用来表示唯一客户端,如果需要指定发送,需要指定发送通过name来区分

        webSocketSet.put(name,this);

        log.info("[WebSocket] 连接成功,当前连接人数为:={}",webSocketSet.size());

    }

  

  

    @OnClose

    public void OnClose(){

        webSocketSet.remove(this.name);

        log.info("[WebSocket] 退出成功,当前连接人数为:={}",webSocketSet.size());

    }

  

    @OnMessage

    public void OnMessage(String message){

        log.info("[WebSocket] 收到消息:{}",message);

        //判断是否需要指定发送,具体规则自定义

        if(message.indexOf("TOUSER") == 0){

            String name = message.substring(message.indexOf("TOUSER")+6,message.indexOf(";"));

            AppointSending(name,message.substring(message.indexOf(";")+1,message.length()));

        }else{

            GroupSending(message);

        }

  

    }

  

    /**

     * 群发

     * @param message

     */

    public void GroupSending(String message){

        for (String name : webSocketSet.keySet()){

            try {

                webSocketSet.get(name).session.getBasicRemote().sendText(message);

            }catch (Exception e){

                e.printStackTrace();

            }

        }

    }

  

    /**

     * 指定发送

     * @param name

     * @param message

     */

    public void AppointSending(String name,String message){

        try {

            webSocketSet.get(name).session.getBasicRemote().sendText(message);

        }catch (Exception e){

            e.printStackTrace();

        }

    }

}

二、客户端实现

HTML5实现:以下就是核心代码了,其实其他博客有很多,本人就不多说了。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

var websocket = null;

   if('WebSocket' in window){

       websocket = new WebSocket("ws://192.168.2.107:8085/websocket/testname");

   }

   websocket.onopen = function(){

       console.log("连接成功");

   }

   websocket.onclose = function(){

       console.log("退出连接");

   }

   websocket.onmessage = function (event){

       console.log("收到消息"+event.data);

   }

   websocket.onerror = function(){

       console.log("连接出错");

   }

   window.onbeforeunload = function () {

       websocket.close(num);

   }

SpringBoot后台实现:本人发现多数博客都是采用js来实现客户端,很少有用后台来实现,所以本人也就写了写,大神请勿喷?。很多时候,项目与项目之间通讯也需要后台作为客户端来连接。

步骤一:首先我们要导入后台连接websocket的客户端依赖

1

2

3

4

5

6

<!--websocket作为客户端-->

<dependency>

    <groupId>org.java-websocket</groupId>

    <artifactId>Java-WebSocket</artifactId>

    <version>1.3.5</version>

</dependency>

 步骤二:把客户端需要配置到springboot容器里面去,以便程序调用。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

package com.example.socket.config;

  

import lombok.extern.slf4j.Slf4j;

import org.java_websocket.client.WebSocketClient;

import org.java_websocket.drafts.Draft_6455;

import org.java_websocket.handshake.ServerHandshake;

import org.springframework.context.annotation.Bean;

import org.springframework.stereotype.Component;

  

import java.net.URI;

  

/**

 * @Description: 配置websocket后台客户端

 */

@Slf4j

@Component

public class WebSocketConfig {

  

    @Bean

    public WebSocketClient webSocketClient() {

        try {

            WebSocketClient webSocketClient = new WebSocketClient(new URI("ws://localhost:8085/websocket/test"),new Draft_6455()) {

                @Override

                public void onOpen(ServerHandshake handshakedata) {

                    log.info("[websocket] 连接成功");

                }

  

                @Override

                public void onMessage(String message) {

                    log.info("[websocket] 收到消息={}",message);

  

                }

  

                @Override

                public void onClose(int code, String reason, boolean remote) {

                    log.info("[websocket] 退出连接");

                }

  

                @Override

                public void onError(Exception ex) {

                    log.info("[websocket] 连接错误={}",ex.getMessage());

                }

            };

            webSocketClient.connect();

            return webSocketClient;

        catch (Exception e) {

            e.printStackTrace();

        }

        return null;

    }

  

}

步骤三:使用后台客户端发送消息

1、首先本人写了一个接口,里面有指定发送和群发消息两个方法。

2、实现发送的接口,区分指定发送和群发由服务端来决定(本人在服务端写了,如果带有TOUSER标识的,则代表需要指定发送给某个websocket客户端)。

3、最后采用get方式用浏览器请求,也能正常发送消息。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

package com.example.socket.code;

  

/**

 * @Description: websocket 接口

 */

public interface WebSocketService {

  

    /**

     * 群发

     * @param message

     */

     void groupSending(String message);

  

    /**

     * 指定发送

     * @param name

     * @param message

     */

     void appointSending(String name,String message);

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

package com.example.socket.chat;

  

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

  

/**

 * @Description: 测试后台websocket客户端

 */

@RestController

@RequestMapping("/websocket")

public class IndexController {

  

    @Autowired

    private WebSocketService webSocketClient;

  

    @GetMapping("/sendMessage")

    public String sendMessage(String message){

        webScoketClient.groupSending(message);

        return message;

    }

}

三、最后

注意:

如果是单例的情况下,这个对象的值都会被修改。

本人就抽了时间Debug了一下,经过下图也可以反映出,能够看出,webSokcetSet中存在三个成员,并且vlaue值都是不同的,所以在这里没有出现对象改变而把之前对象改变的现象。

服务端这样写是没问题的。

最后总结:在实际WebSocket服务端案例中为什么没有出现这种情况,当WebSokcet这个类标识为服务端的时候,每当有新的连接请求,这个类都是不同的对象,并非单例。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

import com.alibaba.fastjson.JSON;

  

import java.util.concurrent.ConcurrentHashMap;

  

/**

 * @Description:

 */

public class TestMain {

  

    /**

     * 用于存所有的连接服务的客户端,这个对象存储是安全的

     */

    private static ConcurrentHashMap<String, Student> webSocketSet = new ConcurrentHashMap<>();

  

    public static void main(String[] args) {

        Student student = Student.getStudent();

        student.name = "张三";

        webSocketSet.put("1", student);

  

        Student students = Student.getStudent();

        students.name = "李四";

        webSocketSet.put("2", students);

  

        System.out.println(JSON.toJSON(webSocketSet));

    }

}

  

/**

 * 提供一个单例类

 */

class Student {

  

    public String name;

  

    private Student() {

    }

  

    private static final Student student = new Student();

  

    public static Student getStudent() {

        return student;

  

    }

}

 打印结果:

1

{"1":{"name":"李四"},"2":{"name":"李四"}}

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

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

相关文章

AI图片智能选区抠像解决方案

高质量的图片处理往往依赖于繁琐的手动操作&#xff0c;耗费大量时间与精力。美摄科技推出了一款革命性的AI图片智能选区抠像解决方案&#xff0c;旨在帮助企业轻松实现图片的高效处理&#xff0c;提升内容创作效率与质量。 美摄科技的AI图片智能选区抠像解决方案&#xff0c;…

AFCI 应用笔记二之数据采集

1. 简介 基于监督学习的神经网络算法需要大量数据作为输入&#xff0c;模型完全由数据驱动&#xff0c;其数据质量是算法有效的必要条件&#xff0c;所以如何高效的采集到数据&#xff0c;以及正确的标注或分析是极其重要的&#xff0c;如果第一步有问题&#xff0c;后续的所有…

C++搭建深度学习的推理框架

我们的目的是:借助C++搭建一个类似于pytorch,tensorflow的深度学习框架,对标pytorch,tensorflow实现对应的功能。由于本人能力有限,下面本人将借助C++搭建一个简单的全连接神经网络,并且尝试解释里面的算子定义和计算图构建。 算子定义 回顾pytorch里面搭建的全连接神经网…

ESP32S3网络编程学习笔记(1)—— Wi-Fi扫描实验

前言 &#xff08;1&#xff09;如果有嵌入式企业需要招聘湖南区域日常实习生&#xff0c;任何区域的暑假Linux驱动/单片机/RTOS的实习岗位&#xff0c;可C站直接私聊&#xff0c;或者邮件&#xff1a;zhangyixu02gmail.com&#xff0c;此消息至2025年1月1日前均有效 &#xff…

基于DPDK的VPP 插件demo代码

VPP的插件编写&#xff0c; 首先要把VPP 工程下载下来&#xff0c; 编译通过。 然后按照example程序的套中来编写插件。 还有一个前提&#xff0c; 就是测试机上已经具备了DPDK 已经可用版本。 1. 下载VPP。 可以从github上下载VPP的指定版本的zip包&#xff0c; 也可以用…

2024年租用阿里云服务器多少钱一年?连夜整理分享

阿里云服务器租用价格表2024年最新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元&#xff0c;ECS u1服务器2核4G5M固定带宽199元一年&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;2核…

__ne__()函数详解

在Python中&#xff0c;ne 是一个特殊方法&#xff0c;用于定义不等于&#xff08;!&#xff09;操作符的行为。当你使用 ! 操作符来比较两个类的实例时&#xff0c;Python会自动调用这个方法。如果这个方法没有在你的类中定义&#xff0c;那么 ! 操作符会使用 eq 方法的结果来…

【C++】C++ primer plus 第十二章--类和动态内存分配

动态内存和类 关于静态数据成员 类之作声明&#xff0c;不分配内存&#xff0c;因此静态成员变量在类中不能进行初始化&#xff0c;需要在类外进行。特殊情况&#xff1a; 存在可以在类中声明静态成员并初始化的情况&#xff0c;成员类型为const整型或者const枚举类型。 特殊…

软考高级架构师:嵌入式系统的内核架构

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

2024/4/1—力扣—二叉树的最近公共祖先

代码实现&#xff1a; 思路&#xff1a; 递归判断左子树和右子树&#xff0c;查找p或者q是否在当前节点的子树上 1&#xff0c;在同一子树上&#xff0c;同一左子树&#xff0c;返回第一个找到的相同值&#xff0c;同一右子树上&#xff0c;返回第一个找到的相同值 2&#xff0…

Oracle23免费版简易安装攻略

installation-guide 1 安装 root用户下 wget https://yum.oracle.com/repo/OracleLinux/OL8/developer/x86_64/getPackage/oracle-database-preinstall-23c-1.0-1.el8.x86_64.rpm wget https://download.oracle.com/otn-pub/otn_software/db-free/oracle-database-free-23c-1…

UML 绘制工具 starUML 入门介绍

拓展阅读 常见免费开源绘图工具 OmniGraffle 创建精确、美观图形的工具 UML-架构图入门介绍 starUML UML 绘制工具 starUML 入门介绍 PlantUML 是绘制 uml 的一个开源项目 UML 等常见图绘制工具 绘图工具 draw.io / diagrams.net 免费在线图表编辑器 绘图工具 excalidr…

linux lua版本升级

要在Linux上升级Lua到5.4版本&#xff0c;你需要执行以下步骤&#xff1a; 1、下载Lua 5.4源代码&#xff1a; 首先&#xff0c;你需要从Lua的官方网站下载Lua 5.4的源代码。你可以访问Lua的官方网站或使用wget或curl命令从命令行下载。 wget http://www.lua.org/ftp/lua-5.4.x…

工具推荐-针对Nacos利器-NacosExploitGUI_v4.0

Nacos是由阿里所开发的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 工具简介 集成Nacos的各种poc Nacos控制台默认口令漏洞(nacos,nacos)Nacostoken.secret.key默认配置(QVD-2023-6271)Nacos-clientYaml反序列化漏洞Nacos Jraft Hessian反序列化漏洞…

代码随想录算法训练营第46天|139.单词拆分|关于多重背包,你该了解这些!|背包问题总结篇!

代码随想录算法训练营第46天|139.单词拆分|关于多重背包&#xff0c;你该了解这些&#xff01;|背包问题总结篇&#xff01; 详细布置 关于 多重背包&#xff0c;力扣上没有相关的题目&#xff0c;所以今天大家的重点就是回顾一波 自己做的背包题目吧。 139.单词拆分 视频讲…

PET-SQL:基于大模型的两阶段Text2SQL方法

简介 PET-SQL出自论文《PET-SQL: A Prompt-enhanced Two-stage Text-to-SQL Framework with Cross-consistency》&#xff0c;将基于大模型的Text2SQL分为两个阶段进行&#xff0c;在第一阶段使用数据表schema信息、数据表采样数据、相似问答问答对生成初步的SQL(PreSQL)&…

【边缘智能】00_边缘计算发展背景

本系列是个人学习《边缘就算基础知识入门》的笔记&#xff0c;仅为个人学习记录&#xff0c;欢迎交流&#xff0c;感谢批评指正 移动物联设备产生海量数据&#xff0c;数据密集型移动智能应用&#xff0c;计算密集、动态性高&#xff0c;实时性强 传统云计算架构 基于广域互联…

大学课堂点名程序

大学课堂点名程序 from gtts import gTTS import os import tkinter as tk import pygame import csv import random from datetime import datetime from tkinter import messagebox from tkinter import simpledialog input_data="student1" def langDu(text):tts…

matrix-breakout-2-morpheus 靶机渗透

信息收集&#xff1a; 1.nmap存活探测&#xff1a; nmap -sn -r 192.168.10.1/24 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-04-06 12:13 CST Nmap scan report for 192.168.10.1 Host is up (0.00056s latency). MAC Address: 00:50:56:C0:00:08 (VMware) Nmap…

鸿蒙内核源码分析 (双向链表篇) | 谁是内核最重要结构体

双向链表是什么&#xff1f; 谁是鸿蒙内核最重要的结构体 &#xff1f; 一定是: LOS_DL_LIST(双向链表)&#xff0c; 它长这样。 typedef struct LOS_DL_LIST {struct LOS_DL_LIST *pstPrev; /**< Current nodes pointer to the previous node | 前驱节点(左手)*/struct L…