websocket中spring注入失效

一个null指针引发的思考

websocket中spring注入失效

  • 一个null指针引发的思考
    • 场景
    • 代码
        • SpringBoot入口类
        • 配置类
        • websocket类
    • 问题
      • 排查
        • 问题1:
        • 问题2:
    • 反思
    • 解决
      • 方案一:
      • 方案二:
      • 方案三:
      • 方案四:

场景

首页有个websocket的连接,初始化的时候需要去后台获取数据,然后会定时5s一次获取后端的数据。

代码

SpringBoot入口类

扫描注册到spring中

package com;import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;@ComponentScan(basePackages = {com.xxx})//扫描com.xxx及子包
@EnableScheduling//开启定时任务
@SpringBootApplication //启动springboot
public class Application implements ApplicationRunner {public static void main(String[] args) throws Exception {SpringApplication.run(Application.class, args);}@Overridepublic void run(ApplicationArguments args) throws Exception {}}
配置类
package com.xxx.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}
websocket类

实现和web前端的交互,获取web后端的数据

package com.xxx.webSocket;import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.xxx.service.IOverviewService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;/*** 首页概况** @author 阿明* @date 2023/11/30-15:39*/
@Slf4j
@ServerEndpoint("/websocket/v3/overview")
@Component
public class WebSocketServerOverview {private static final int CARD = 5;private static final Map<String, DataWrap<OverviewVo>> dataWrapMap = new ConcurrentHashMap<>();@Resourceprivate IOverviewService overviewService;@Scheduled(cron = "*/5 * * * * ? ")public void sendCard() throws InterruptedException {try {for (DataWrap<OverviewVo> value : dataWrapMap.values()) {OverviewVo overviewData = overviewService.card();//new CardVo(totalDatas, cls, toDay, history, totalRules, use, cpu, hardDisk, memory, traffic);value.getSession().getBasicRemote().sendText(JSONUtil.toJsonStr(overviewData));}} catch (IOException e) {log.error("websocket overview错误:", e);}}/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session) {log.info("连接成功");}/*** 连接关闭调用的方法*/@OnClosepublic void onClose(Session session) {Iterator<DataWrap<OverviewVo>> iterator = dataWrapMap.values().iterator();while (iterator.hasNext()) {DataWrap<OverviewVo> value = iterator.next();if (value.getSession().equals(session)) {//清除缓存数据 value.getType()iterator.remove();}}log.info("连接关闭");}/*** 收到客户端消息后调用的方法,第一次连接成功,这里会发送一次消息** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, Session session) {JSONObject jsonObject = JSONUtil.parseObj(message);//无效消息,避免发送心跳解析失败if (jsonObject.isNull("userId")) {return;}String userId = (String) jsonObject.get("userId");Integer type = (Integer) jsonObject.get("type");Integer dataId = null;if (!jsonObject.isNull("dataId")) {dataId = (Integer) jsonObject.get("dataId");}if (!dataWrapMap.containsKey(userId + "_" + type) || dataWrapMap.containsKey(userId + "_" + type) && !Objects.equals(dataWrapMap.get(userId + "_" + type).getDataId(), dataId)) {DataWrap<OverviewVo> dataWrap = new DataWrap<>(userId, type, dataId, session, new LinkedList<>());try {switch (type) {case CARD:dataWrapMap.put(userId + "_" + type, dataWrap);OverviewVo overviewData = overviewService.card();//overviewService会是null;// OverviewVo overviewData = SpringUtil.getBean(IOverviewService.class).card();session.getBasicRemote().sendText(JSONUtil.toJsonStr(overviewData));break;default:break;}} catch (IOException e) {log.error("websocket overview错误:", e);}}log.info("收到..消息:" + message);}/*** @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error) {Iterator<DataWrap<OverviewVo>> iterator = dataWrapMap.values().iterator();while (iterator.hasNext()) {DataWrap value = iterator.next();if (value.getSession().equals(session)) {iterator.remove();}}log.error("发生错误", error);}
}

问题

小A问我他项目遇到个问题,前端页面先和后端建立连接,等连接成功后,前端会发送个{“type”:5,“userId”:“admin-uuid”}给到后端,开始的时候用的@Scheduled注解的sendCard方法5s一执行,执行到overviewService正常返回数据,今天测试说,你这个一进来没数据,等5s才有数据,想让首页一进来就有数据,所以他就打算前端发送上来数据直接去查库,返回一次数据,返回的时候OnMessage注解的onMessage方法中overviewService属性一直为空,想不到为啥为null。

排查

  • 这个时候的思路肯定是执行的OnMessage注解的onMessage方法没走spring的bean,具体是为啥,开始分析,经过排查发现
问题1:

Tomcat 在 org.apache.tomcat.websocket.server.WsServerContainer 里注册 @ServerEndpoint

@Override
public void addEndpoint(Class<?> clazz) throws DeploymentException {ServerEndpoint annotation = clazz.getAnnotation(ServerEndpoint.class);if (annotation == null) {throw new DeploymentException("Missing @ServerEndpoint annotation");}ServerEndpointConfig sec = ServerEndpointConfig.Builder.create(clazz, annotation.value()).build();addEndpoint(sec);
}

📌 关键点

  • Tomcat 通过 clazz.getAnnotation(ServerEndpoint.class) 发现 @ServerEndpoint 标注的类
  • Tomcat 直接 new 这个类(它不会用 Spring 方式去创建 Bean)
  • Spring 的 @Component@Autowired 机制不会生效
问题2:

其实这个不算问题,算是为什么。

@Scheduled 是由 Spring 管理的,所以 @Autowired 可以用。
@ServerEndpoint 由 Tomcat 创建,不是 Spring Bean,所以 @Autowired 不能用。
💡 如果想在 WebSocket 里用 @Autowired 的 Bean,可以用 staticSpringContextUtil 获取。

Spring 类加载器加载的@Scheduled 注解的类,WebSocket 容器类加载器加载的@ServerEndpoint 注解的类。

反思

  • 做java的一直用spring,虽然spring帮我们做了很多事,但是也让我们养成了懒惰的思维,习惯了spring的依赖注入,然后想当然的认为都可以直接依赖使用,这种惯性思维导致了这种问题。

解决

方案一:

可以注释掉overviewService使用SpringUtil.getBean(IOverviewService.class)替代,这种直接使用spring的上下文直接取IOverviewService类对象,肯定是取到了,直接用就行。

方案二:

使用SpringConfigurator 来注入 Spring Bean

package com.xxx.autoconfig;import cn.hutool.extra.spring.SpringUtil;
import org.springframework.context.ApplicationContext;import javax.websocket.server.ServerEndpointConfig;public class SpringConfigurator extends ServerEndpointConfig.Configurator {@Overridepublic <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException {ApplicationContext applicationContext = SpringUtil.getApplicationContext();if (applicationContext == null) {throw new InstantiationException("Spring ApplicationContext is null");}return applicationContext.getBean(clazz);}
}
@ServerEndpoint("/websocket/v3/overview")改为
@ServerEndpoint(value = "/websocket/v3/overview", configurator = SpringConfigurator.class)

方案三:

  • 使用 @Component + ServerEndpointExporter没管用,证明WebSocket 端点的实例仍然不是由 Spring 管理的,而是由 Tomcat管理的。最终看源码:

    package org.springframework.web.socket.server.standard;
    public class ServerEndpointExporter extends WebApplicationObjectSupportimplements InitializingBean, SmartInitializingSingleton {protected void registerEndpoints() {Set<Class<?>> endpointClasses = new LinkedHashSet<>();if (this.annotatedEndpointClasses != null) {endpointClasses.addAll(this.annotatedEndpointClasses);}ApplicationContext context = getApplicationContext();if (context != null) {String[] endpointBeanNames = context.getBeanNamesForAnnotation(ServerEndpoint.class);for (String beanName : endpointBeanNames) {//这里虽然会执行,但是最终的这个bean是放到tomcat里边了endpointClasses.add(context.getType(beanName));}}for (Class<?> endpointClass : endpointClasses) {registerEndpoint(endpointClass);}if (context != null) {Map<String, ServerEndpointConfig> endpointConfigMap = context.getBeansOfType(ServerEndpointConfig.class);for (ServerEndpointConfig endpointConfig : endpointConfigMap.values()) {registerEndpoint(endpointConfig);}}}
    

    源码主要是这里tomcat-embed-websocket-9.0.39.jar

    package org.apache.tomcat.websocket.server; 
    public class WsServerContainer extends WsWebSocketContainerimplements ServerContainer {void addEndpoint(Class<?> pojo, boolean fromAnnotatedPojo) throws DeploymentException {if (deploymentFailed) {throw new DeploymentException(sm.getString("serverContainer.failedDeployment",servletContext.getContextPath(), servletContext.getVirtualServerName()));}ServerEndpointConfig sec;try {ServerEndpoint annotation = pojo.getAnnotation(ServerEndpoint.class);if (annotation == null) {throw new DeploymentException(sm.getString("serverContainer.missingAnnotation",pojo.getName()));}String path = annotation.value();// Validate encodersvalidateEncoders(annotation.encoders());// ServerEndpointConfig 这里使用了Configurator,这里就是为啥方案二能成功的原因。Class<? extends Configurator> configuratorClazz =annotation.configurator();Configurator configurator = null;if (!configuratorClazz.equals(Configurator.class)) {try {configurator = annotation.configurator().getConstructor().newInstance();} catch (ReflectiveOperationException e) {throw new DeploymentException(sm.getString("serverContainer.configuratorFail",annotation.configurator().getName(),pojo.getClass().getName()), e);}}//这里直接拿到这个类从tomcat生成了sec = ServerEndpointConfig.Builder.create(pojo, path).decoders(Arrays.asList(annotation.decoders())).encoders(Arrays.asList(annotation.encoders())).subprotocols(Arrays.asList(annotation.subprotocols())).configurator(configurator).build();} catch (DeploymentException de) {failDeployment();throw de;}addEndpoint(sec, fromAnnotatedPojo);}
    

方案四:

  • 见网上好多用@EnableWebSocket的我是没成功,去官网找的用@EnableWebSocketMessageBroker这种更好,格式更规范

  • 用spring自己的websocketGetting Started | Using WebSocket to build an interactive web application

  • git clone https://github.com/spring-guides/gs-messaging-stomp-websocket.git

接受实体类HelloMessage

package com.example.messagingstompwebsocket;public class HelloMessage {private String name;public HelloMessage() {}public HelloMessage(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

发送实体类Greeting

package com.example.messagingstompwebsocket;public class Greeting {private String content;public Greeting() {}public Greeting(String content) {this.content = content;}public String getContent() {return content;}}

控制层GreetingController

package com.example.messagingstompwebsocket;import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import org.springframework.web.util.HtmlUtils;@Controller
public class GreetingController {@MessageMapping("/hello")@SendTo("/topic/greetings")public Greeting greeting(HelloMessage message) throws Exception {Thread.sleep(1000); // simulated delayreturn new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");}}

配置类WebSocketConfig

package com.example.messagingstompwebsocket;import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {@Overridepublic void configureMessageBroker(MessageBrokerRegistry config) {config.enableSimpleBroker("/topic");//配置订阅消息的目标前缀config.setApplicationDestinationPrefixes("/app");//配置应用程序的目的地前缀}@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("/gs-guide-websocket");//配置端点}}

启动类MessagingStompWebsocketApplication

package com.example.messagingstompwebsocket;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class MessagingStompWebsocketApplication {public static void main(String[] args) {SpringApplication.run(MessagingStompWebsocketApplication.class, args);}
}

主页面index.html

<!DOCTYPE html>
<html>
<head><title>Hello WebSocket</title><link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"><link href="/main.css" rel="stylesheet"><script src="https://code.jquery.com/jquery-3.1.1.min.js"></script><script src="https://cdn.jsdelivr.net/npm/@stomp/stompjs@7.0.0/bundles/stomp.umd.min.js"></script><script src="/app.js"></script>
</head>
<body>
<noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websocket relies on Javascript beingenabled. Please enableJavascript and reload this page!</h2></noscript>
<div id="main-content" class="container"><div class="row"><div class="col-md-6"><form class="form-inline"><div class="form-group"><label for="connect">WebSocket connection:</label><button id="connect" class="btn btn-default" type="submit">Connect</button><button id="disconnect" class="btn btn-default" type="submit" disabled="disabled">Disconnect</button></div></form></div><div class="col-md-6"><form class="form-inline"><div class="form-group"><label for="name">What is your name?</label><input type="text" id="name" class="form-control" placeholder="Your name here..."></div><button id="send" class="btn btn-default" type="submit">Send</button></form></div></div><div class="row"><div class="col-md-12"><table id="conversation" class="table table-striped"><thead><tr><th>Greetings</th></tr></thead><tbody id="greetings"></tbody></table></div></div>
</div>
</body>
</html>

app.js

const stompClient = new StompJs.Client({brokerURL: 'ws://localhost:8080/gs-guide-websocket'
});stompClient.onConnect = (frame) => {setConnected(true);console.log('Connected: ' + frame);stompClient.subscribe('/topic/greetings', (greeting) => {showGreeting(JSON.parse(greeting.body).content);});
};stompClient.onWebSocketError = (error) => {console.error('Error with websocket', error);
};stompClient.onStompError = (frame) => {console.error('Broker reported error: ' + frame.headers['message']);console.error('Additional details: ' + frame.body);
};function setConnected(connected) {$("#connect").prop("disabled", connected);$("#disconnect").prop("disabled", !connected);if (connected) {$("#conversation").show();}else {$("#conversation").hide();}$("#greetings").html("");
}function connect() {stompClient.activate();
}function disconnect() {stompClient.deactivate();setConnected(false);console.log("Disconnected");
}function sendName() {stompClient.publish({destination: "/app/hello",body: JSON.stringify({'name': $("#name").val()})});
}function showGreeting(message) {$("#greetings").append("<tr><td>" + message + "</td></tr>");
}$(function () {$("form").on('submit', (e) => e.preventDefault());$( "#connect" ).click(() => connect());$( "#disconnect" ).click(() => disconnect());$( "#send" ).click(() => sendName());
});

main.css

body {background-color: #f5f5f5;
}#main-content {max-width: 940px;padding: 2em 3em;margin: 0 auto 20px;background-color: #fff;border: 1px solid #e5e5e5;-webkit-border-radius: 5px;-moz-border-radius: 5px;border-radius: 5px;
}

在这里插入图片描述

启动项目

访问 http://localhost:8080/
点击connect
What is your name?输入名字点击send

Greetings下显示响应结果

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

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

相关文章

QT开发(4)--各种方式实现HelloWorld

目录 1. 编辑框实现 2. 按钮实现 前面已经写过通过标签实现的了&#xff0c;所以这里就不写了&#xff0c;通过这两个例子&#xff0c;其他的也是同理 1. 编辑框实现 编辑框分为单行编辑框&#xff08;QLineEdit&#xff09;双行编辑框&#xff08;QTextEdit&#xff09;&am…

自由学习记录(45)

顶点片元着色器&#xff08;important&#xff09; 1.需要在Pass渲染通道中编写着色器逻辑 2.可以使用cG或HLSL两种shader语言去编写Shader逻辑 3.代码量较多&#xff0c;灵活性较强&#xff0c;性能消耗更可控&#xff0c;可以实现更多渲染细节 4.适用于光照处理较少&#xf…

内存管理(C++篇)

前言 我们在C语言阶段学习过内存管理的相关操作和知识&#xff0c;比如说malloc&#xff0c;calloc等内存开辟函数&#xff0c;但我们在学的时候会发现&#xff0c;使用这些函数还是相对来说比较冗杂的&#xff0c;那么今天我们来学习C语言中相关的内存管理操作&#xff0c;相信…

母婴电商企业案例:日事清驱动项目管理执行与OKR目标管理的流程自动化实践

一、关于科木电商 “小鹿豆豆”&#xff0c;一个年轻的品牌&#xff0c;近期在无论是淘宝、拼多多还是抖音电商平台&#xff0c;都成了亮眼的爆品。这个由绵阳科木电子商务有限公司推出的新品牌&#xff0c;以其高品质的保湿云柔巾迅速赢得了母婴护理市场的青睐&#xff0c;特别…

图数据库Neo4j和JDK安装与配置教程(超详细)

目录 前言 一、Java环境配置 &#xff08;一&#xff09;JDK的下载与安装 &#xff08;二&#xff09;JDK环境配置 &#xff08;三&#xff09;检测JDK17是否配置成功 二、Neo4j的安装与配置 &#xff08;一&#xff09;Neo4j的下载与安装 &#xff08;二&#xff09;N…

git原理与常用命令及其使用

认识工作区、暂存区、版本库 ⼯作区&#xff1a;是在电脑上你要写代码或⽂件的⽬录。 暂存区&#xff1a;英⽂叫 stage 或 index。⼀般存放在 .git ⽬录下的 index ⽂件&#xff08;.git/index&#xff09;中&#xff0c;我们 把暂存区有时也叫作索引&#xff08;index&#xf…

Web-Machine-N7靶机通关攻略

获取靶机ip arp-scan -l 端口扫描 nmap xxxx 访问80端口发现没用 扫描目录 gobuster dir -u http:/192.168.117.160 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium,txt -x php,html,txt ,zip 打开exploit.html 点击F12&#xff0c;修改localhost为靶机ip&#…

2025-03-21 Unity 网络基础3——TCP网络通信准备知识

文章目录 1 IP/端口类1.1 IPAddress1.2 IPEndPoint 2 域名解析2.1 IPHostEntry2.2 Dns 3 序列化与反序列化3.1 序列化3.1.1 内置类型 -> 字节数组3.1.2 字符串 -> 字节数组3.1.3 类对象 -> 字节数组 3.2 反序列化3.2.1 字节数组 -> 内置类型3.2.2 字节数组 -> 字…

Java-servlet(七)详细讲解Servlet注解

Java-servlet&#xff08;七&#xff09;详细讲解Servlet注解 前言一、注解的基本概念二、Override 注解2.1 作用与优势2.2 示例代码 三、Target 注解3.1 定义与用途3.2 示例代码 四、WebServlet 注解4.1 作用4.2 示例代码 五、反射与注解5.1 反射的概念5.2 注解与反射的结合使…

nginx 反向代理 ubuntu

关键字 Nginx&#xff0c;正向代理&#xff0c;方向代理&#xff0c;博客建站 背景环境 我在搭建个人博客的过程中遇到一个问题&#xff0c;我的博客服务的端口是1313&#xff0c;我的域名是qinyangx.top。我希望能够通过qinyangx.top直接访问到服务器上1313端口的博客服务。…

学习threejs,使用TextGeometry文本几何体

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.TextGeometry1.1.1 ☘…

【秣厉科技】LabVIEW工具包——OpenCV 教程(12):机器学习

文章目录 前言机器学习例1&#xff1a;支持向量机&#xff08;SVM&#xff09;做平面向量二分类例2&#xff1a; K邻近算法&#xff08;KNearest&#xff09;实现分类 总结 前言 需要下载安装OpenCV工具包的朋友&#xff0c;请前往 此处 &#xff1b;系统要求&#xff1a;Wind…

企业级AI架构探索:业务驱动,场景优先

企业级AI架构的设计需要兼顾技术先进性、业务适配性、成本效益和长期可维护性。以下从架构设计原则、核心架构层次、基础框架可能性、实施路径四个维度进行系统性阐述&#xff1a; 一、设计原则 业务驱动&#xff0c;场景优先 明确AI解决的业务痛点&#xff08;如降本增效、智…

DCDC36V同步降压 输出可调 2A电流恒压芯片SL1588H 替换LV3842

在当今电子设备飞速发展的时代&#xff0c;电源管理芯片的性能优劣直接关乎设备的稳定性与高效运行。对于诸多需要将 36V 电压进行同步降压、输出电压可调且稳定输出 2A 电流的应用场景&#xff0c;一款卓越的恒压芯片不可或缺。SL1588H 正凭借其领先的技术和出色的性能&#x…

Beans模块之工厂模块注解模块@Qualifier

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

flutter 开发web端的性能优化

参考资料 Flutter for Web 首次首屏优化 ——JS 分片优化_main.dart.js-CSDN博客文章浏览阅读1.4k次。本文介绍了如何通过延迟加载组件和js分片优化Flutter for Web应用的加载速度。在实践中&#xff0c;通过按需加载减少js文件大小&#xff0c;使用并行加载提升加载效率。通过…

【设计模式】三十二、策略模式

系列文章|源码 https://github.com/tyronczt/design-mode-learn 文章目录 系列文章|源码一、模式定义与核心思想二、模式结构与Java实现1. 核心角色2. Java代码示例 三、策略模式的五大核心优势四、适用场景五、与其他模式的对比六、最佳实践建议总结 &#x1f680;进阶版【更…

【Linux 维测专栏 1 -- Hung Task 分析与验证】

文章目录 Linux Hung Task 简介1. Hung Task 概述2. D 状态与 Hung Task3. Hung Task 的工作原理4. Hung Task 的配置5. Hung Task 的典型输出6. Hung Task 的应用场景7. kernel 配置7.1 编译选项7.2 参数控制7.3 验证方法4. 扩展接口 8. 注意事项 Linux Hung Task 简介 1. Hu…

计算机网络精讲day1——计算机网络的性能指标(上)

性能指标1&#xff1a;速率 概念1&#xff1a;比特 英文全称是binary digit&#xff0c;意思是一个二进制数字&#xff0c;因此一个比特就是二进制数字中的1或0&#xff0c;比特也是信息论中使用的信息量单位。 概念2&#xff1a;速率 网络中的速率指的是数据的传送速率&#…

ubuntu20.04使用matlab2024a快捷键调整

一、概述 因为最近在使用ubuntu系统&#xff0c;在上面安装一个matlab比较方便&#xff0c;不用来回在window上面进行跳转&#xff0c;节省不少时间&#xff0c;同时在ubuntu下面启动matlab速度也比较快。 二、问题解决 &#xff08;一&#xff09;问题概述 问题如下&#xf…