WebSocket总结和Demo

el/2024/4/20 14:19:15

定义

WebSocket 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。一开始的握手需要借助HTTP请求完成。 WebSocket是真正实现了全双工通信的服务器向客户端推的互联网技术。 它是一种在单个TCP连接上进行全双工通讯协议。Websocket通信协议与2011年倍IETF定为标准RFC 6455,Websocket API被W3C定为标准。

全双工和单工的区别?

  • 全双工(Full Duplex)是通讯传输的一个术语。通信允许数据在两个方向上同时传输,它在能力上相当于两个单工通信方式的结合。全双工指可以同时(瞬时)进行信号的双向传输(A→B且B→A)。指A→B的同时B→A,是瞬时同步的。
  • 单工、半双工(Half Duplex),所谓半双工就是指一个时间段内只有一个动作发生,举个简单例子,一条窄窄的马路,同时只能有一辆车通过,当目前有两辆车对开,这种情况下就只能一辆先过,等到头儿后另一辆再开,这个例子就形象的说明了半双工的原理。早期的对讲机、以及早期集线器等设备都是基于半双工的产品。随着技术的不断进步,半双工会逐渐退出历史舞台。

http与websocket的区别

http

http协议是短连接,因为请求之后,都会关闭连接,下次重新请求数据,需要再次打开链接。

websocket

WebSocket协议是一种长链接,只需要通过一次请求来初始化链接,然后所有的请求和响应都是通过这个TCP链接进行通讯。

Demo

这里使用SpringBoot搭建Websocket项目实例

服务端

新建SpringBoot项目,修改pom.xml文件导入依赖坐标

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.dustdawn</groupId><artifactId>websocketDemo</artifactId><version>1.0-SNAPSHOT</version><!--springboot父级依赖当前的项目就是Spring Boot项目用来提供相关的Maven默认依赖。使用它之后,常用的包依赖可以省去version标签--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.5.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><dependencies><!--springboot 整合Web组件整合SpringMVC 就会把传统方式的SpringMVC依赖的jar全部给下载来 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--热部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><version>2.0.1.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><!--导入模板引擎依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency></dependencies>
</project>

新建SpringBoot启动类Application

package com.dustdawn;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//springboot启动类注解
@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class);}
}

很简单,这个时候springboot项目就搭建好了

WebSocket配置

新建websocket配置类,实现WebSocketConfigurer接口,重写registerWebSocketHandlers方法,这是一个核心实现方法,配置websocket入口,允许访问的域、注册Handler、SockJs支持和拦截器。

package com.dustdawn.websocket;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;@Configuration
@EnableWebSocket
public class websocketconfig implements WebSocketConfigurer {@Autowiredprivate MyHandshakeInterceptor myHandshakeInterceptor;@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {webSocketHandlerRegistry.addHandler(myHandler(),"/ws").setAllowedOrigins("*").addInterceptors(myHandshakeInterceptor);}@Beanpublic WebSocketHandler myHandler() {return new MyHandler();}
}
  • registry.addHandler注册和路由的功能,当客户端发起websocket连接,把/path交给对应的handler处理,而不实现具体的业务逻辑,可以理解为收集和任务分发中心。
  • setAllowedOrigins(String[] domains),允许指定的域名或IP(含端口号)建立长连接,如果只允许自家域名访问,这里轻松设置。如果不限时使用"*"号,如果指定了域名,则必须要以http或https开头。
  • addInterceptors,顾名思义就是为handler添加拦截器,可以在调用handler前后加入我们自己的逻辑代码。

Handler类和拦截器类如下

package com.dustdawn.websocket;import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;import java.io.IOException;
//配置handler
public class MyHandler extends TextWebSocketHandler {public void handleTextMessage(WebSocketSession session, TextMessage message)throws IOException {System.out.println("获取到消息 >> " + message.getPayload());session.sendMessage(new TextMessage("消息已收到"));if (message.getPayload().equals("10")) {for (int i = 0; i < 10; i++) {session.sendMessage(new TextMessage("消息 -> " + i));try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}}@Overridepublic void afterConnectionEstablished(WebSocketSession session) throwsException {session.sendMessage(new TextMessage("欢迎连接到ws服务"));}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status)throws Exception {System.out.println("断开连接!");}
}
package com.dustdawn.websocket;import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;import java.util.Map;/*** 配置拦截器*/
@Component
public class MyHandshakeInterceptor implements HandshakeInterceptor {public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponseresponse, WebSocketHandler wsHandler, Map<String, Object> attributes) throwsException {//将用户id放入socket处理器的会话(WebSocketSession)中attributes.put("uid", 1001);System.out.println("开始握手。。。。。。。");return true;}@Overridepublic void afterHandshake(ServerHttpRequest request, ServerHttpResponseresponse, WebSocketHandler wsHandler, Exception exception) {System.out.println("握手成功啦。。。。。。");}
}

测试

使用测试工具网站测试

easywoole
besjon
在这里插入图片描述在这里插入图片描述

在这里插入图片描述在这里插入图片描述

使用HTML页面测试

因为springboot推荐使用模板引擎theymeleaf对静态资源进行访问,这里导入springboot整合theymeleaf的依赖后,在resource目录下新建templates目录
在这里插入图片描述
然后编写Controller跳转到我们的testWebsocket.html

package com.dustdawn.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
public class IndexController {@RequestMapping("/index")public String index() {return "testWebsocket";}
}

testWebsocket.html内容

<!DOCTYPE html>
<html>
<head><title>Java后端WebSocket的Tomcat实现</title><meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport' /><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>Welcome<br/><input id="text" type="text"/><button onclick="send()">发送消息</button><hr/><button onclick="closeWebSocket()">关闭WebSocket连接</button><hr/>
<div id="message"></div>
</body><script type="text/javascript">var websocket = null;//判断当前浏览器是否支持WebSocketif ('WebSocket' in window) {websocket = new WebSocket("ws://localhost:8080/ws");}else {alert('当前浏览器 Not support websocket')}//连接发生错误的回调方法websocket.onerror = function () {setMessageInnerHTML("WebSocket连接发生错误");};//连接成功建立的回调方法websocket.onopen = function () {setMessageInnerHTML("WebSocket连接成功");}//接收到消息的回调方法websocket.onmessage = function (event) {setMessageInnerHTML(event.data);}//连接关闭的回调方法websocket.onclose = function () {setMessageInnerHTML("WebSocket连接关闭");}//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function () {closeWebSocket();}//将消息显示在网页上function setMessageInnerHTML(innerHTML) {document.getElementById('message').innerHTML += innerHTML + '<br/>';}//关闭WebSocket连接function closeWebSocket() {websocket.close();}//发送消息function send() {var message = document.getElementById('text').value;websocket.send(message);}
</script>
</html>

启动项目,地址导航http://localhost:8080/index
在这里插入图片描述

可以看到,通过Handler处理,在页面连接到websocket页面后,首先客户端打印出执行js的
websocket.onopen事件的回调函数后的内容,然后再收到服务端发送的消息,执行js中websocket.onmessage方法

在这里插入图片描述
点击发送后调用websocket.send方法,向服务端发送请求信息
服务端通过自定义的Handle中实现父类的基类接口(WebSocketHandler)中的handleTextMessage方法,其中的TextMessage对象取出接收到的信息进行处理。最后通过WebSocketSession对象的sendMessage方法发送到客户端请求方。

在这里插入图片描述


http://www.ngui.cc/el/2927075.html

相关文章

微信小程序常用方法

定时器 that.setData({timeid: setInterval(function () {that.getAlertList("");}, 10000)})clearInterval(this.data.timeid);延时器 setTimeout(function () {//要延时执行的代码wx.clearStorage();app.globalData.user ;app.globalData.token ;app.globalDat…

微服务项目专业术语

SaaS&#xff1a;软件即服务 SOA&#xff1a;面向服务 RPC&#xff1a;远程过程调用 RMI&#xff1a;远程方法调用 PV&#xff1a;(page view)&#xff0c;即页面浏览量&#xff1b; 用户每1次对网站中的每个网页访问均被记录1次。用户对同一页面的多次访问&#xff0c;访问…

ES5和6的一些新特性

let:声明一个变量&#xff0c;不会越界 const&#xff1a;声明一个常量 字符串扩展API includes&#xff1a;返回布尔值&#xff0c;表示是否找到了参数字符串。 startsWith&#xff1a;返回布尔值&#xff0c;表示参数字符串是否在原字符串的头部。 endsWith&#xff1a;返回…

select2清除选择,重置

清空option并且将选中内容置空 $("#specs option").remove(); $("#specs").select2(“val”, “”);

服务器,IP,域名关系

公网IP 我们的本地搭建的服务器只能本地访问&#xff0c;如何通过外网访问呢&#xff1f;只能通过公网IP。 而一般电信服务商提供的公网IP都是动态的&#xff08;一定时间会变化&#xff09;&#xff0c;所以不能通过一个固定的IP进行访问。这个时候就需要我们去申请购买公网固…

Nginx反向代理解决端口映射问题

通过修改本地hosts文件实现将自定义的域名解析映射成本地localhost的地址&#xff0c;只需要通过域名加端口号就可以实现通过localhost访问本地服务器一样的效果 进一步优化如何值通过域名而不需要端口号进行访问呢&#xff1f;这就需要用到反向代理工具Nginx了 nginx可以作为…

【算法】回溯法解决八皇后问题

八皇后问题&#xff0c;是一个古老而著名的问题&#xff0c;是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯贝瑟尔于1848年提出&#xff1a;在88格的国际象棋上摆放八个皇后&#xff0c;使其不能互相攻击&#xff0c;即任意两个皇后都不能处于同一行、同一列或同一斜线上…

【算法】击鼓传花

解题思路见注释 /*** author dustdawn* date 2019/9/2 8:24*/ public class JiGuChuanHua {public static void main(String[] args) {int n 3; //人数int m 3; //次数transmit(n, m);}public static void transmit(int n, int m) {int[][] arr new int[m1][n1];/*** 定义 行…

单例模式实现的多种方式

文章目录饿汉式构建懒汉式线程安全构建静态内置类实现单例模式线程安全的单例模式: 双重检验锁(DCL)饿汉式构建 饿汉式&#xff0c;线程不安全 是否 Lazy 初始化&#xff1a;是 是否多线程安全&#xff1a;否 实现难度&#xff1a;易 描述&#xff1a;这种方式是最基本的实…

【算法】小米9.11笔试:《2048》

《2048》是一款热门的数字游戏。游戏中&#xff0c;每个方块上的数字都有2的幂&#xff0c;数字方块会根据指令整体进行上下左右移动&#xff0c;如果两个数字相同的方块在移动中碰撞&#xff0c;他们就会合成一个新的方块。例如下图为4*4格子的游戏&#xff0c;0表示格子为空&…