• WebSocket——相关介绍以及后端配置


    一、WebSocket介绍:

            WebSocket是一种在单个TCP连接上进行全双工通信的协议,旨在改进客户端和服务器之间的实时通信。以下是关于WebSocket的详细介绍:

    1、定义与标准

    • WebSocket是独立的、创建在TCP上的协议,通过HTTP/1.1协议的101状态码进行握手。
    • WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。

    2、工作原理

    • WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。
    • 在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

    3、特点

    1. 实时性:由于协议是全双工的,服务器可以随时主动给客户端下发数据,相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少。
    2. 较少的控制开销:在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小。在不包含扩展的情况下,对于服务器到客户端的内容,此头部大小只有2至10字节(和数据包长度有关);对于客户端到服务器的内容,此头部还需要加上额外的4字节的掩码。
    3. 保持连接状态:与HTTP不同的是,Websocket需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。
    4. 更好的二进制支持:Websocket定义了二进制帧,相对HTTP,可以更轻松地处理二进制内容。
    5. 跨域支持:WebSocket协议可以跨域使用,允许不同源的客户端与服务器进行通信。

    4、用途

            WebSocket特别适合需要连续数据交换的服务,如网络游戏、实时交易系统、在线聊天应用、实时协作编辑、实时数据展示、在线游戏、实时地图应用、在线投票系统、实时监控系统以及实时消息推送等。

    5、帧结构

            WebSocket的通信以帧为单位进行,帧的结构包括RSV1、RSV2、RSV3(默认为0,仅当使用extension扩展时,有扩展决定其值)、opcode(帧的类型)、FIN(表示消息的结尾)以及消息长度等内容。

    二、WebSocket后端配置:

    step1:首先是依赖下载:

            下面是一般项目的常用依赖:

    1. <dependencies>
    2. <dependency>
    3. <groupId>junitgroupId>
    4. <artifactId>junitartifactId>
    5. <version>4.12version>
    6. dependency>
    7. <dependency>
    8. <groupId>com.alibabagroupId>
    9. <artifactId>fastjsonartifactId>
    10. <version>2.0.25version>
    11. dependency>
    12. <dependency>
    13. <groupId>org.apache.commonsgroupId>
    14. <artifactId>commons-lang3artifactId>
    15. <version>3.14.0version>
    16. dependency>
    17. <dependency>
    18. <groupId>com.auth0groupId>
    19. <artifactId>java-jwtartifactId>
    20. <version>4.3.0version>
    21. dependency>
    22. <dependency>
    23. <groupId>org.springframework.bootgroupId>
    24. <artifactId>spring-boot-starter-websocketartifactId>
    25. dependency>
    26. <dependency>
    27. <groupId>org.dom4jgroupId>
    28. <artifactId>dom4jartifactId>
    29. <version>2.1.3version>
    30. dependency>
    31. <dependency>
    32. <groupId>cn.hutoolgroupId>
    33. <artifactId>hutool-allartifactId>
    34. <version>5.8.10version>
    35. dependency>
    36. <dependency>
    37. <groupId>org.projectlombokgroupId>
    38. <artifactId>lombokartifactId>
    39. dependency>
    40. <dependency>
    41. <groupId>org.springframework.bootgroupId>
    42. <artifactId>spring-boot-starter-webartifactId>
    43. dependency>
    44. <dependency>
    45. <groupId>org.springframework.bootgroupId>
    46. <artifactId>spring-boot-starter-web-servicesartifactId>
    47. dependency>
    48. <dependency>
    49. <groupId>org.mybatis.spring.bootgroupId>
    50. <artifactId>mybatis-spring-boot-starterartifactId>
    51. <version>3.0.3version>
    52. dependency>
    53. <dependency>
    54. <groupId>com.mysqlgroupId>
    55. <artifactId>mysql-connector-jartifactId>
    56. <scope>runtimescope>
    57. dependency>
    58. <dependency>
    59. <groupId>org.projectlombokgroupId>
    60. <artifactId>lombokartifactId>
    61. <optional>trueoptional>
    62. dependency>
    63. <dependency>
    64. <groupId>org.springframework.bootgroupId>
    65. <artifactId>spring-boot-starter-testartifactId>
    66. <scope>testscope>
    67. dependency>
    68. <dependency>
    69. <groupId>org.mybatis.spring.bootgroupId>
    70. <artifactId>mybatis-spring-boot-starter-testartifactId>
    71. <version>3.0.3version>
    72. <scope>testscope>
    73. dependency>
    74. <dependency>
    75. <groupId>org.assertjgroupId>
    76. <artifactId>assertj-coreartifactId>
    77. dependency>
    78. dependencies>

    step2:然后是定义配置类:

            GetHttpSession:

    1. package com.example.cqcrhouduan.config;
    2. import jakarta.servlet.http.HttpSession;
    3. import jakarta.websocket.HandshakeResponse;
    4. import jakarta.websocket.server.HandshakeRequest;
    5. import jakarta.websocket.server.ServerEndpointConfig;
    6. public class GetHttpSession extends ServerEndpointConfig.Configurator {
    7. @Override
    8. public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response){
    9. // 获取httpSession对象
    10. HttpSession httpSession = (HttpSession) request.getHttpSession();
    11. // 将httpSession保存起来
    12. sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
    13. }
    14. }

            WebsocketConfig:

    1. package com.example.cqcrhouduan.config;
    2. import jakarta.websocket.server.ServerEndpoint;
    3. import org.springframework.context.annotation.Bean;
    4. import org.springframework.context.annotation.Configuration;
    5. import org.springframework.web.socket.server.standard.ServerEndpointExporter;
    6. @Configuration
    7. public class WebsocketConfig {
    8. @Bean
    9. public ServerEndpointExporter serverEndpointExporter(){
    10. return new ServerEndpointExporter();
    11. }
    12. }

     step3:然后是定义相关工具和信息类:

            Message:

    1. package com.example.cqcrhouduan.pojo;
    2. import lombok.AllArgsConstructor;
    3. import lombok.Data;
    4. import lombok.NoArgsConstructor;
    5. @Data
    6. @AllArgsConstructor
    7. @NoArgsConstructor
    8. public class Message {
    9. private String toName;
    10. private String message;
    11. }

             MessageUtil:

    1. package com.example.cqcrhouduan.pojo;
    2. import com.alibaba.fastjson.JSON;
    3. public class MessageUtil {
    4. public static String getMessage(boolean isSystemMessage,String fromName,Object message){
    5. ResultMessage result = new ResultMessage();
    6. result.setSystem(isSystemMessage);
    7. result.setMessage(message);
    8. if(fromName != null){
    9. result.setFormName(fromName);
    10. }
    11. return JSON.toJSONString(result);
    12. }
    13. }

            ChatEndPoint:

    1. package com.example.cqcrhouduan.pojo;
    2. import com.alibaba.fastjson.JSON;
    3. import com.example.cqcrhouduan.config.GetHttpSession;
    4. import jakarta.servlet.http.HttpSession;
    5. import jakarta.websocket.*;
    6. import jakarta.websocket.server.ServerEndpoint;
    7. import org.springframework.stereotype.Component;
    8. import java.util.Map;
    9. import java.util.Set;
    10. import java.util.concurrent.ConcurrentHashMap;
    11. @ServerEndpoint(value = "/chat",configurator = GetHttpSession.class)
    12. @Component
    13. public class ChatEndPoint {
    14. private static final Map onlineUser = new ConcurrentHashMap<>();
    15. private HttpSession httpSession;
    16. @OnOpen
    17. public void onOpen(Session session, EndpointConfig config){
    18. this.httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
    19. String user = (String) this.httpSession.getAttribute("user");
    20. // 1、将session进行保存
    21. onlineUser.put(user,session);
    22. // 2、广播消息,将所有登录的用户推送给所有的用户
    23. String message = MessageUtil.getMessage(true,null,getFriends());
    24. broadcastAllUser(message);
    25. }
    26. private void broadcastAllUser(String Message){
    27. try{
    28. // 遍历map集合
    29. Set> entries = onlineUser.entrySet();
    30. for(Map.Entry entry : entries){
    31. // 获取所有用户对应的session对象
    32. Session session = entry.getValue();
    33. session.getBasicRemote().sendText(Message);
    34. }
    35. }catch (Exception e){
    36. // 记录日志等等
    37. }
    38. }
    39. public Set getFriends(){
    40. Set set = onlineUser.keySet();
    41. return set;
    42. }
    43. @OnMessage
    44. public void opMessage(String message){
    45. try{
    46. // 将消息推送给指定的用户:
    47. Message msg = JSON.parseObject(message,Message.class);
    48. //获取 消息接收方的名称
    49. String toNmae = msg.getToName();
    50. String mes = msg.getMessage();
    51. Session session = onlineUser.get(toNmae);
    52. String user = (String) this.httpSession.getAttribute("user");
    53. String mess = MessageUtil.getMessage(false,user,mes);
    54. session.getBasicRemote().sendText(mess);
    55. }catch (Exception e){
    56. // log
    57. }
    58. }
    59. @OnClose
    60. public void onClose(Session session){
    61. String user = (String) this.httpSession.getAttribute("user");
    62. // 1.从onlinesUser中剔除当前用户
    63. onlineUser.remove(user);
    64. // 2.通知其它所有的用户
    65. String message = MessageUtil.getMessage(true,null,getFriends());
    66. broadcastAllUser(message);
    67. }
    68. }

            ResultMessage:

    1. package com.example.cqcrhouduan.pojo;
    2. import lombok.AllArgsConstructor;
    3. import lombok.Data;
    4. import lombok.NoArgsConstructor;
    5. @Data
    6. @NoArgsConstructor
    7. @AllArgsConstructor
    8. public class ResultMessage {
    9. private boolean System;
    10. private String formName;
    11. private Object Message;
    12. }

     至此关于Socket利用session来获取信息的后端类的配置就全部完成了,后面将会继续提供前端的配置方法。<( ̄︶ ̄)>!

  • 相关阅读:
    华为云云耀云服务器L实例评测|企业项目最佳实践之私有库搭建verdaccio(八)
    Nginx之动静分离解读
    循环结构:for循环,while循环,do-while,死循环
    使用 Docker 部署 instantbox 轻量级 Linux 系统
    sql注入
    Nomad 系列-Nomad+Traefik+Tailscale 集成实现零信任安全
    什么,api竟然有版本
    论文翻译1-----DSSM:Deep Structured Semantic Models
    Centos - SSH 服务搭建
    MySQL实现的一点总结(三)
  • 原文地址:https://blog.csdn.net/weixin_74996125/article/details/139204286