WebSocket

一. WebSocket概述

  • 在后端服务器与服务器之间,HTTP请求是可以相互发送的,但是在浏览器与服务器之间,HTTP请求只能从浏览器发起,方向固定,不能从服务器往浏览器主动去发起HTTP请求。

问题:服务器无法直接向浏览器发送请求(HTTP协议的缺陷)

常见替代方案:轮询,浏览器给服务器不断地发送请求询问支付结果。

轮询缺陷:

  • 浪费带宽(因为浏览器会不断地给服务器发送请求)
  • 实时性差(并不是服务器知道结果以后,浏览器那边就能立刻知道,要等到浏览器下一次去询问的时候才能知道结果)
  • 服务器压力大(特别是像促销之类的活动,服务器会收到大量的询问订单结果的请求)

1.1 WebSocket协议

  • 2008年提出,2011年成为标准
  • 最早是HTML5新增的协议,现在基本所有的语言都支持
  • 作用:可以在浏览器和服务器之间建立一个全双工的通信通道(就是浏览器既可以往服务器发请求,服务器也可以往浏览器发请求,这就叫一个全双工的通信协议)

1.2 WebSocket实现浏览器与服务器的通信流程 / 过程

 1. 浏览器发起HTTP请求,请求建立WebSocket连接

  • 在浏览器发起的HTTP请求当中,URL是以ws:开头的,而不是之前见到的http或者https开头的。ws是WebSocket的缩写。

 2. 服务器响应同意协议更改

  • 服务器响应同意协议更改,会响应一个101的状态码,切换协议的意思

3.  相互发送数据

  • 绿色箭头代表的是浏览器向服务器发送的消息,红色箭头代表的是服务器向浏览器发送的消息

 

1.3 WebSocket底层原理 

  • WebSocket协议建立在TCP协议基础上的,所以服务器端也容易实现,不同的语言都有支持
  • TCP协议是全双工协议,HTTP协议基于它,但设计成了单向的
  • WebSocket协议是对HTTP协议的一个补充,某一些HTTP做不到的场景WebSocket来补充它
  • WebSocket没有同源限制(同一个IP,同一个端口叫同源,就是浏览器端的地址和服务器端的地址它的IP端口是一致的,这就叫同源)
  • 什么是不同源,就是IP端口不一致的。
  • 现在前后端分离项目经常就是不同源的,前端会起一个端口比如8081,后端会起一个端口比如9091,此时前端去访问后端就会存在这个不同源的一个限制,就是会存在一个跨域异常。
  • 可以通过前端配代理去解决或者上到服务器上可以通过Nginx反向代理去解决这个跨域问题。
  • 因为WebSocket没有同源限制,所以即使你的前端的源和后端的源不一致,也不影响WebSocket请求的发送。

二. Java实现WebSocket的两种方式

使用Spring封装

在Spring里面已经帮我们实现了WebSocket的基本功能,它完成了HTTP协议升级为WebSocket协议的这个过程,封装了通信,以及完成了很多的通信细节的功能。

我们并不是要去实现WebSocket这个功能的后端开发,我们要做的就是在Spring给我们提供的实现了WebSocket功能的基础之上去完成一些业务功能的开发,这些业务的功能可以有两种方式来实现:

  • 一种是比较简单的,基于Java注解的方式
  • 另一种是基于Spring提供的上层封装,它有很多应用级别的封装,我们用它去开发的话,会比较的快捷和方便。

 3.1 基于Java注解实现WebSocket服务器端

 

LomBok依赖可以让我们更方便的去打印日志,同时它还提供一些注解可以快速的给实体类生成Getter、Setter方法。

package com.gch.java;import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
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;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/**监听WebSocket客户端地址/myWs谁来连接了WebSocket服务端*/
@ServerEndpoint("/myWs")
@Component // 声明为一个Bean
@Slf4j
public class WsServerEndpoint {// 有多个客户端来连接,应该使用线程安全的CurrentHashMappublic static Map<String,Session> sessionMap = new ConcurrentHashMap<>();// 当WebSocket客户端连接WebSocket服务端的时候,我们需要来声明一下我们的服务端去做哪些事情// 连接建立时执行的操作@OnOpen// 每一个WebSocket连接对于服务端来说都是一个sessionpublic void onOpen(Session session){sessionMap.put(session.getId(),session);log.info("websocket is open");}// 监听通信// 当WebSocket客户端浏览器给WebSocket服务器发消息的时候,我服务器做什么事情// 收到了客户端消息执行的操作@OnMessagepublic String onMessage(String text){log.info("收到了一条信息:" + text);return "已收到你的消息";}// 监听到连接关闭时执行的操作@OnClosepublic void onClose(Session session){sessionMap.remove(session.getId(),session);log.info("websocket is close");}// 每隔多少毫秒去执行一次定时任务给客户端发送xx@Scheduled(fixedRate = 2000)public void sendMsg() throws IOException {for(String key: sessionMap.keySet()){sessionMap.get(key).getBasicRemote().sendText("心跳");}}// 现在,Spring框架并不能扫描到我们的服务终端,我们还需要再加一个配置类// HTTP加上S之后它是一个更安全的传输
}
package com.gch.java;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** 配置类* 注入Spring WebSocket框架里的一个对象叫做ServerEndpointExporter*/
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}
}
package com.gch;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;@EnableScheduling // 开启定时任务
@SpringBootApplication
public class WebsocketQuickstartApplication {public static void main(String[] args) {SpringApplication.run(WebsocketQuickstartApplication.class, args);}}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>ws client</title>
</head>
<body>
</body><script>let ws = new WebSocket("ws://localhost:8080/myWs")ws.onopen = function (){ws.send("hello")}ws.onmessage = function (message) {console.log(message.data)}
</script>
</html>

 3.3   基于Spring框架实现WebSocket服务器端

Spring框架已经在应用层面去帮我们定义了一些接口和抽象类,我们只要实现这些接口和抽象类,就能够完成一个目录比较清晰的WebSocket的服务器端,并且它里面有很多封装的功能我们可以直接使用。

 

 

 

 

 

 

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

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

相关文章

curl常用命令

1、curl -v url&#xff1a;默认发出Get请求&#xff0c;查看页面源码&#xff0c;显示一次通信过程&#xff0c;包含请求头、响应头、返回内容 2、curl -i url&#xff1a; 显示响应头、返回内容body 3、curl -I url&#xff1a;只显示响应头 4、curl url&#xff1a;默认使…

如何检查自己的笔记本电池是否需要更换(电池自检)

1.检查电池实际可充电量&#xff1a; ①winR键 ②输入 powercfg/batteryreport ③根据提示打开网址 如果相差太多就需要更换电池啦

苹果 MacBook Pro 笔记本电脑 更换电池教程(图文、视频)

问题 我平时日常用机是mac和thinkpad&#xff0c;如果不做微信和ios相关的开发的时候&#xff0c;我喜欢用thinkpad。最近一段时间就是这样&#xff0c;所以有一段时间没用这台15年的mac a1398了。春节回家&#xff0c;收拾电脑&#xff0c;感觉触摸板不太对劲&#xff0c;细看…

无人模型锂聚合物电池使用(上)——部分受损电芯无法充电时强制使用(强烈不推荐,仅限于应急,事后应尽快更换电池)

目录 1.出现3s电池一节电芯受损鼓包&#xff0c;其他电芯正常&#xff0c;无法使用balance模式充入电池&#xff0c;连接平衡头不识别​编辑 2.先不连接平衡头&#xff0c;仅连接正负极&#xff0c;直接选择charge模式&#xff08;不使用balance模式&#xff09;充电。 3.充…

电池保护板 - 问题归纳

电池保护板 - 问题归纳 简介充电锂电池磷酸铁锂电池 放电总结 最近更新日期&#xff1a;2023-03-07 简介 电池充放电过程中&#xff0c;如果电压、电流或温度等参数不稳定或超出电池的安全范围&#xff0c;就会对电池造成损害&#xff0c;甚至可能引发安全事故。为了保护电池的…

为什么有的锂电保护板需要激活之锂电池保护板怎么激活

1.什么是锂电池保护板&#xff1f;   锂电池保护板是对串联锂电池组的充放电保护&#xff1b;在充满电时能保证各单体电池之间的电压差异小于设定值&#xff08;一般20mV&#xff09;&#xff0c;实现电池组各单体电池的均充&#xff0c;有效地改善了串联充电方式下的充电效果…

Linux静态库文件

静态库的优点 不想让用户知道自己的代码实现&#xff0c;却又让用户使用功能&#xff0c;就将写好的代码放到库文件中&#xff08;也可以减少每次源码进行编译的时间&#xff0c;.c文件到可执行文件需要时间&#xff09;。方法如下 ar crv libtemp.a fitst.o second.o//demo …

工作积极主动分享,善于业务沟通

工作积极主动分享&#xff0c;善于业务沟通 目录概述需求&#xff1a; 设计思路实现思路分析1.工作积极主动承担责任2.善于沟通3.一起常常lauch 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;…

chatgpt赋能python:Python中的开方指令:介绍和使用

Python中的开方指令&#xff1a;介绍和使用 Python是一种流行的编程语言&#xff0c;广泛用于数据科学、机器学习、Web开发和其他领域。在许多情况下&#xff0c;需要对数值进行数学计算&#xff0c;其中包括开方运算。Python中有多种方法可以执行开方运算&#xff0c;本文将介…

从源码学习Transformer

Transformer总体结构 近几年NLP领域有了突飞猛进的发展&#xff0c;预训练模型功不可没。当前利用预训练模型&#xff08;pretrain models&#xff09;在下游任务中进行fine-tune&#xff0c;已经成为了大部分NLP任务的固定范式。Transformer摒弃了RNN的序列结构&#xff0c;完…

Oracle函数——COALESCE

Oracle函数——COALESCE COALESCE 含义&#xff1a;COALESCE是一个函数&#xff0c; (expression_1, expression_2, ...,expression_n)依次参考各参数表达式&#xff0c;遇到非null值即停止并返回该值。如果所有的表达式都是空值&#xff0c;最终将返回一个空值。使用COALESC…

Oracle 函数编写

CREATE OR REPLACE FUNCTION f_homestay_count (wkt_poly CLOB ) RETURN NUMBER IS result NUMBER ; BEGINSELECTCOUNT (*) INTO resultFROMHOMESTAY_BASIC TWHEREsdo_anyinteract (T .geom_point,sdo_geometry (wkt_poly, 4326)) TRUE; RETURN (result) ;END ;因为之前都是…

Oracle函数【详细 包括举例】

概述 Oracle SQL 提供了用于执行特定操作的专用函数。这些函数大大增强了 SQL 语言的功能。函数可以接受零个或者多个输入参数&#xff0c;并返回一个输出结果。 Oracle 数据库中主要使用两种类型的函数&#xff1a; 1. 单行函数&#xff1a;对每一个函数应用在表的记录中时&a…

oracle常用函数

1.sign sign函数是根据给的数为正数&#xff0c;就返回1,0返回0&#xff0c;负数返回-1。需要注意sign&#xff08;这个括号里面只能是个字段&#xff09;&#xff0c;在括号中写个子查询直接就报错了&#xff01; 2.decode 用法&#xff1a; decode(条件,值1,返回值1,值2,返回…

重庆“90后”双胞胎“动妹” 守护春运回家路

近日&#xff0c;在重庆客运段动车一队值乘的G8508次列车上&#xff0c;有一对“90后”双胞胎姐妹乘务员&#xff0c;名字叫李清和李洁&#xff0c;她们也是一同参加工作。图为双胞胎姐妹整理着装准备工作。 据悉&#xff0c;双胞胎姐妹已经在列车上共同经历了8个春运。姐妹俩说…

联想Win10安装Ubuntu双系统教程

前言&#xff1a;最近为了更好的做一名程序员&#xff08;猿&#xff09;&#xff0c;所以准备装一个双系统&#xff0c;也就是Ubuntu系统&#xff0c;网上坑太多&#xff0c;所以决定自己写一点操作步骤 首先看一下我的计算机配置&#xff0c;联想小新700 Tip&#xff1a;这里…

轮胎规格怎么看

轮胎规格怎么看&#xff0c;很多车主都会问这样的问题&#xff0c;只看到轮胎上的字&#xff0c;却不清楚这些字代表的是什么意思&#xff0c;鉴于此&#xff0c;小编今天就来普及一下轮胎规格知识。 轮胎规格怎么看 我们今天大家讲解一下轮胎胎壁上的标示都代表了那些含义&…

如何安装linux和windows双系统

像我们运维学习者&#xff0c;平常会用到linux&#xff0c;但是又必不可免的会用到windows&#xff0c;所以在一台电脑上安装linux和windows双系统就成了刚需&#xff0c;那么如何来安装windows和linux双系统呢 实验环境 电脑&#xff1a;实验室台式机 优盘&#xff1a;金士…

算法技巧——双指针算法

前置知识 C 和 C 的数组、指针。 什么是双指针 严格的来说&#xff0c;双指针只能说是是算法中的一种技巧。 双指针指的是在遍历对象的过程中&#xff0c;不是普通的使用单个指针进行访问&#xff0c;而是使用两个相同方向&#xff08;快慢指针&#xff09;或者相反方向&am…