WebSocket实现聊天

基于webSocket通信的库主要有 socket.io,SockJS,这次用的是 SockJS。

这里我们使用sockjs-client、stomjs这两个模块,要实现webSocket通信,需要后台配合,也使用相应的模块。

WebSocket

1、http:http超文本传输协议,http有1.0、1.1、 2.0几个版本,从http1.1起,默认都开启了Keep-Alive,保持连接持续性,简单地说,当一个网页打开完成后,客户端和服务器之间用于传输http数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接,这样就降低了资源的消耗优化性能,但是Keep-Alive也是有时间限制的,还有一个客户端只能主动发起请求才能获取返回数据,并不能主动接收后台推送的数据,websocket便应运而生。

2、websocket:是 html5 新增加特性之一,目的是浏览器与服务端建立全双工的通信方式,解决 http 请求-响应带来过多的资源消耗,同时对特殊场景应用提供了全新的实现方式,比如聊天、股票交易、游戏等对对实时性要求较高的行业领域。

http与websocket都是基于TCP(传输控制协议)的,websocket可以看做是对http协议的一个补充。

WebSocket协议提供了通过一个套接字实现全双工通信的功能。除了其他的功能之外,它能够实现Web浏览器和服务器之间的异步通信。全双工意味着服务器可以发送消息给浏览器,浏览器也可以发送消息给服务器。

3、SockJs:SockJS是一个JavaScript库,为了应对许多浏览器不支持WebSocket协议的问题,设计了备选SockJs。SockJS 是 WebSocket 技术的一种模拟。SockJS会尽可能对应 WebSocket API,但如果WebSocket 技术不可用的话,会自动降为轮询的方式。

SockJS会优先选择WebSocket进行连接,但是当服务器或客户端不支持WebSocket时,会自动在 XHR流、XDR流、iFrame事件源、iFrame HTML文件、XHR轮询、XDR轮询、iFrame XHR轮询、JSONP轮询 这几个方案中择优进行连接。

4、Stompjs:STOMP—— Simple Text Oriented Message Protocol——面向消息的简单文本协议。SockJS 为 WebSocket 提供了 备选方案。但无论哪种场景,对于实际应用来说,这种通信形式层级过低。

STOMP协议,来为浏览器 和 server 间的 通信增加适当的消息语义。

5、WebSocket、SockJs、STOMP三者关系

简而言之,WebSocket 是底层协议,SockJS 是WebSocket 的备选方案,也是底层协议,而 STOMP 是基于 WebSocket(SockJS)的上层协议。

(1)HTTP协议解决了 web 浏览器发起请求以及 web 服务器响应请求的细节,假设 HTTP 协议 并不存在,只能使用 TCP 套接字来 编写 web 应用,那将是一件非常痛苦的事情。

(2)直接使用 WebSocket(SockJS) 就很类似于 使用 TCP 套接字来编写 web 应用,因为没有高层协议,就需要我们定义应用间所发送消息的语义,还需要确保连接的两端都能遵循这些语义;

(3)同HTTP在TCP 套接字上添加请求-响应模型层一样,STOMP在WebSocket 之上提供了一个基于帧的线路格式层,用来定义消息语义;

SockJS

WebSocket是一个相对比较新的规范,在Web浏览器和应用服务器上没有得到一致的支持。所以我们需要一种WebSocket的备选方案,而这恰恰是SockJS所擅长的。

SockJS是WebSocket技术的一种模拟,在表面上,它尽可能对应WebSocket API,但是在底层非常智能。如果WebSocket技术不可用的话,就会选择另外的通信方式。

使用SockJS

只需加上withSockJS()方法就能声明我们想要使用SockJS功能,如果WebSocket不可用的话,SockJS的备用方案就会发挥作用。

同时需要注意的是,如果我们不是使用 SockJS,那么后端代码就只需要把这个 withSockJS() 去掉即可,那么就会采用 websocket 来连接。

sockjs-client

sockjs-client是从SockJS中分离出来的用于客户端使用的通信模块,所以我们就直接来看看SockJS。

SockJS是一个浏览器的JavaScript库,它提供了一个类似于网络的对象,SockJS提供了一个连贯的、跨浏览器的JavaScriptAPI,它在浏览器和Web服务器之间创建了一个低延迟、全双工、跨域通信通道。

你可能会问,我为什么不直接用原生的WebSocket而要使用SockJS呢?

这得益于SockJS的一大特性,一些浏览器中缺少对WebSocket的支持,因此回退选项是必要的,而Spring框架提供了基于SockJS协议的透明的回退选项。SockJS提供了浏览器兼容性,优先使用原生的WebSocket,如果某个浏览器不支持WebSocket,SockJS会自动降级为轮询。

stomjs

STOMP(Simple Text-Orientated Messaging Protocol) 面向消息的简单文本协议,WebSocket是一个消息架构,不强制使用任何特定的消息协议,它依赖于应用层解释消息的含义。

与HTTP不同,WebSocket是处在TCP上非常薄的一层,会将字节流转化为文本/二进制消息,因此,对于实际应用来说,WebSocket的通信形式层级过低,因此可以在 WebSocket 之上使用STOMP协议,来为浏览器 和 server间的通信增加适当的消息语义。

STOMP与WebSocket 的关系

HTTP协议解决了web浏览器发起请求以及web服务器响应请求的细节,假设HTTP协议不存在,只能使用TCP套接字来编写web应用,你可能认为这是一件疯狂的事情

直接使用WebSocket(SockJS)就很类似于使用TCP套接字来编写web应用,因为没有高层协议,就需要我们定义应用间发送消息的语义,还需要确保连接的两端都能遵循这些语义。

同HTTP在TCP套接字上添加请求-响应模型层一样,STOMP在WebSocket之上提供了一个基于帧的线路格式层,用来定义消息语义。

前端代码实现:

先安装 sockjs-client 和 stompjs

npm install sockjs-client
npm install stompjs
<script>import SockJS from 'sockjs-client'import Stomp from 'stompjs'export default {......methods: {......// 连接后台connection () {let that = this// 建立连接对象let sockUrl = '/api/***?token=' + this.token.substring(7) + '&abc=' + this.$route.params.idlet socket = new SockJS(sockUrl)// 获取STOMP子协议的客户端对象this.stompClient = Stomp.over(socket)// 定义客户端的认证信息,按需求配置let headers = {Authorization: ''}// 向服务器发起websocket连接this.stompClient.connect(headers, (res) => {// 订阅服务端提供的某个topicthis.stompClient.subscribe('/topic/***/' + this.$route.params.id, (frame) => {that.addBarage(JSON.parse(frame.body))})that.sentFirst()}, (err) => {console.log('失败:' + err)})this.stompClient.debug = null},// 断开连接disconnect () {if (this.stompClient) {this.stompClient.disconnect()}},// 初始化websocketinitWebSocket () {this.connection()let that = this// 断开重连机制,尝试发送消息,捕获异常发生时重连this.timer = setInterval(() => {try {that.stompClient.send('connect-test')} catch (err) {console.log('断线了: ' + err)that.connection()}}, 5000)},// 用户加入发送弹幕keyDown (e) {if (e.keyCode === 13) {if (e.preventDefault) {e.preventDefault()} else {window.event.returnValue = false}this.sentBarrage()}}},mounted () {this.initWebSocket()},beforeDestroy () {if (this.player) {this.player.dispose()this.player = null}// 页面离开时断开连接,清除定时器this.disconnect()clearInterval(this.timer)}}
</script>
JavaScript客户端代码

要在客户端使用SockJS,需要确保加载了SockJS客户端库。

<script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script>

除了加载SockJS客户端库外,要使用SockJS只需要修改两行代码即可:

var url = 'marco';
var sock = new SockJS(url);
//SockJS所处理的URL是http://或https://,不再是ws://和wss://

运行效果一样,但是客户端–服务器之间通信的方式却有了很大的变化。

使用STOMP消息

STOMP在WebSocket之上提供了一个基于帧的线路格式层,用来定义消息的语义。

STOMP帧由命令、一个或多个头信息以及负载所组成。

STOMP命令是SEND,表明会发送一些内容。紧接着是两个头信息:一个用来表示消息要发送到哪里的目的地,另外一个则包含了负载的大小。然后,紧接着是一个空行,STOMP帧的最后是负载内容。

STOMP帧中最有意思的是destination头信息了。它表明STOMP是一个消息协议。消息会发布到某个目的地,这个目的地实际上可能真的有消息代理作为支撑。另一方面,消息处理器也可以监听这些目的地,接收所发送过来的消息。

启用STOMP消息功能

WebSocketStompConfig 重载了registerStompEndpoints() 方法,将/marcopolo注册为STOMP端点。

这个路径与之前接收和发送消息的目的地路径有所不同。这是一个端点,客户端在订阅或发布消息到目的地前,要连接该端点。

WebSocketStompConfig还通过重载configureMessageBroker() 方法配置了一个简单的消息代理。这个方法是可选的,如果不重载它的话,将会自动配置一个简单的内存消息代理,用它来处理以“/topic”为前缀的消息。

处理来自客户端的STOMP消息

<script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script>
<script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
<script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.js"></script>
<script>
var url = 'http://'+window.location.host+'/yds/marcopolo';
var sock = new SockJS(url);  //创建SockJS连接。
var stomp = Stomp.over(sock);//创建STOMP客户端实例。实际上封装了SockJS,这样就能在WebSocket连接上发送STOMP消息。
var payload = JSON.stringify({'message':'Marco!'});
stomp.connect('guest','guest',function(frame){stomp.send("/app/marco",{},payload);stomp.subscribe('/app/subscribe', function(message){});
});
</script> 

发送消息到客户端

如果你想要在接收消息的时候,同时在响应中发送一条消息,那么需要做的仅仅是将内容返回就可以了。

stomp.subscribe('/topic/marco', function(message){    // 订阅后将会接收到消息。
});

为目标用户发送消息

image.png

为指定用户发送消息

stomp.subscribe('/users/1/message', function(message){ 
});

客户端接收一对一消息的主题是"/users/“+usersId+”/message",这里的用户Id可以是一个普通字符串,只要每个客户端都使用自己的Id并且服务器端知道每个用户的Id就行了。

具体前端如何实现

创建STOMP客户端

在web浏览器中使用普通的Web Socket

STOMP javascript 客户端会使用 ws://的URL与STOMP 服务端进行交互。

为了创建一个STOMP客户端 js 对象,你需要使用 Stomp.client(url),而这个URL连接着服务端的WebSocket的代理

var url = "ws://localhost:61614/stomp";
var client = Stomp.client(url);

Stomp.client(url, protocols)也可以用来覆盖默认的subprotocols。第二个参数可以是一个字符串或一个字符串数组去指定多个subprotocols。

在web浏览器中使用定制的WebSocket

浏览器提供了不同的WebSocket的协议,一些老的浏览器不支持WebSocket的脚本或者使用别的名字。默认下,stomp.js会使用浏览器原生的WebSocket class去创建WebSocket。

但是利用 Stomp.over(ws)这个方法可以使用其他类型的 WebSockets,这个方法得到一个满足WebSocket定义的对象。例如,可以使用由 SockJS实现的Websocket。

如果使用原生的 Websocket 就使用 Stomp.client(url),如果需要使用其他类型的 Websocket(例如由SockJS包装的Websocket)就使用Stomp.over(ws)。除了初始化有差别,Stomp API 在这两种方式下是相同的。

在 node.js程序中

通过stompjs npm package同样也可以在node.js程序中使用这个库。

// 安装
npm install stompjs

在node.js中,require这个模块:var Stomp = require(‘stompjs’);

为了与建立在TCP socket的STOMP-broker连接,使用Stomp.overTCP(host, port)方法。

var client = Stomp.overTCP('localhost', 61613);

为了与建立在Web Socket的STOMP broker连接,使用Stomp.overWS(url)方法。

var client = Stomp.overWS('ws://localhost:61614/stomp');

除了初始化不同,无论是浏览器还是node.js环境下,Stomp API都是相同的。

连接服务端

一旦 Stomp 客户端建立了,必须调用它的 connect()方法去连接 Stomp 服务端进行验证。这个方法需要两个参数,用户的登录和密码凭证。这种情况下,客户端会使用Websocket打开连接,并发送一个 CONNECT frame。

这个连接是异步进行的:你不能保证当这个方法返回时是有效连接的。为了知道连接的结果,你需要一个回调函数。

var connect_callback = function() {// called back after the client is connected and authenticated to the STOMP server
};

但是如果连接失败会发生什么呢?

connect()方法接受一个可选的参数(error_callback),当客户端不能连接上服务端时,这个回调函数error_callback会被调用,该函数的参数为对应的错误对象。

var error_callback = function(error) {// display the error's message header:alert(error.headers.message);
};

在大多数情况下,connect()方法可接受不同数量的参数来提供简单的API:

client.connect(login, passcode, connectCallback);
client.connect(login, passcode, connectCallback, errorCallback);
client.connect(login, passcode, connectCallback, errorCallback, host);

login和passcode是strings,connectCallback和errorCallback则是functions。(有些brokers(代理)还需要传递一个host(String类型)参数。)

如果你需要附加一个headers头部,connect方法还接受其他两种形式的参数:

client.connect(headers, connectCallback);
client.connect(headers, connectCallback, errorCallback);

header是map形式,connectCallback和errorCallback为functions。

需要注意:如果你使用上述这种方式,你需要自行在headers添加login、passcode(甚至host):

var headers = {login: 'mylogin',passcode: 'mypasscode',// additional header'client-id': 'my-client-id'
};
client.connect(headers, connectCallback);

断开连接时,调用disconnect方法,这个方法也是异步的,当断开成功后会接收一个额外的回调函数的参数。如下所示。

client.disconnect(function() {alert("See you next time!");
};

当客户端与服务端断开连接,就不会再发送或接收消息了。

Heart-beating

如果STOMP broker(代理)接收STOMP 1.1版本的帧,heart-beating是默认启用的。

heart-beating也就是频率,incoming是接收频率,outgoing是发送频率。通过改变incoming和outgoing可以更改客户端的heart-beating(默认为10000ms):

client.heartbeat.outgoing = 20000; 
// client will send heartbeats every 20000ms
client.heartbeat.incoming = 0;
// client does not want to receive heartbeats
// from the server

heart-beating是利用window.setInterval()去规律地发送heart-beats或者检查服务端的heart-beats。

发送消息

当客户端与服务端连接成功后,可以调用 send()来发送STOMP消息。这个方法必须有一个参数,用来描述对应的STOMP的目的地。另外可以有两个可选的参数:headers,object类型包含额外的信息头部;body,一个String类型的参数。

client.send("/queue/test", {priority: 9}, "Hello, STOMP");
// client会发送一个STOMP发送帧给/queue/test,
这个帧包含一个设置了priority为9的header和内容为“Hello, STOMP”的body。

client.send(destination, {}, body);

如果你想发送一个有body的信息,也必须传递headers参数。如果没有headers需要传递,那么就传{}即可。

订阅(Subscribe)和接收(receive)消息

为了在浏览器中接收消息,STOMP客户端必须先订阅一个目的地 destination。

你可以使用subscribe()去订阅。这个方法有2个必需的参数:目的地(destination),回调函数(callback);还有一个可选的参数headers。其中destination是String类型,对应目的地,回调函数是伴随着一个参数的function类型。

var subscription = client.subscribe("/queue/test", callback);

subscribe()方法返回一个object,这个object包含一个id属性,对应这个这个客户端的订阅ID。

而unsubscribe()可以用来取消客户端对这个目的地destination的订阅。

默认情况下,如果没有在headers额外添加,这个库会默认构建一个独一无二的ID。在传递headers这个参数时,可以使用你自己的ID。

var mysubid = '...';
var subscription = client.subscribe(destination, callback, { id: mysubid });

这个客户端会向服务端发送一个STOMP订阅帧(SUBSCRIBE frame)并注册回调事件。每次服务端向客户端发送消息时,客户端都会轮流调用回调函数,参数为对应消息的STOMP帧对象(Frame object)。

subscribe()方法,接受一个可选的headers参数用来标识附加的头部。

var headers = {ack: 'client', 'selector': "location = 'Europe'"};
client.subscribe("/queue/test", message_callback, headers);

这个客户端指定了它会确认接收的信息,只接收符合这个selector : location = 'Europe’的消息。

如果想让客户端订阅多个目的地,你可以在接收所有信息的时候调用相同的回调函数:

onmessage = function(message) {// called every time the client receives a message
}
var sub1 = client.subscribe("queue/test", onmessage);
var sub2 = client.subscribe("queue/another", onmessage)

如果要中止接收消息,客户端可以在subscribe()返回的object对象调用unsubscribe()来结束接收。

var subscription = client.subscribe(...);
...
subscription.unsubscribe();

支持JSON

STOMP消息的body必须为字符串。如果你需要发送/接收JSON对象,你可以使用JSON.stringify()和JSON.parse()去转换JSON对象。

Acknowledgment(确认)

默认情况,在消息发送给客户端之前,服务端会自动确认(acknowledged)。

客户端可以选择通过订阅一个目的地时设置一个ack header为client或client-individual来处理消息确认。

在下面这个例子,客户端必须调用message.ack()来通知服务端它已经接收了消息。

var subscription = client.subscribe("/queue/test",function(message) {// do something with the message...// and acknowledge itmessage.ack();},{ack: 'client'}
);

ack()接受headers参数用来附加确认消息。例如,将消息作为事务(transaction)的一部分,当要求接收消息时其实代理(broker)已经将ACK STOMP frame处理了。

var tx = client.begin();
message.ack({ transaction: tx.id, receipt: 'my-receipt' });
tx.commit();

nack()也可以用来通知STOMP 1.1.brokers(代理):客户端不能消费这个消息。与ack()方法的参数相同。

事务(Transactions)

可以在将消息的发送和确认接收放在一个事务中。

客户端调用自身的begin()方法就可以开始启动事务了,begin()有一个可选的参数transaction,一个唯一的可标识事务的字符串。如果没有传递这个参数,那么库会自动构建一个。这个方法会返回一个object。这个对象有一个id属性对应这个事务的ID,还有两个方法:

  • commit()提交事务
  • abort()中止事务

在一个事务中,客户端可以在发送/接受消息时指定transaction id来设置transaction。

// start the transaction
var tx = client.begin();
// send the message in a transaction
client.send("/queue/test", {transaction: tx.id}, "message in a transaction");
// commit the transaction to effectively send the message
tx.commit();

如果你在调用send()方法发送消息的时候忘记添加transction header,那么这不会称为事务的一部分,这个消息会直接发送,不会等到事务完成后才发送。

var txid = "unique_transaction_identifier";
// start the transaction
var tx = client.begin();
// oops! send the message outside the transaction
client.send("/queue/test", {}, "I thought I was in a transaction!");
tx.abort(); // Too late! the message has been sent

调试

有一些测试代码能有助于你知道库发送或接收的是什么,从而来调试程序。

客户端可以将其debug属性设置为一个函数,传递一个字符串参数去观察库所有的debug语句。默认情况,debug消息会被记录在在浏览器的控制台。

client.debug = function(str) {// append the debug log to a #debug div somewhere in the page using JQuery:$("#debug").append(str + "\n");
};

使用情况

1、var error_callback = function(error) {};第一次连接失败和连接后断开连接都会调用这个函数

2、关闭控制台调试数据:设置client.debug = null 就可以,stompjs会去检测debug是否是函数,不是函数就不会调用输出。

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

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

相关文章

2024-2-26-进程线程通信作业

课上代码&#xff1a; sem.h #ifndef _SEM_H_ #define _SEM_H_int open_sem(int semcount); int P(int semid,int semno); int V(int semid,int semno); int del_sem(int semid);#endif sem.c #include <myhead.h> union semun {int val;struct semid_ds *buf;unsign…

【web APIs】1、(学习笔记)有案例!

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、概念二、使用步骤1.获取DOM对象2.操作元素内容3.属性修改3.1.常用属性修改3.2.控制样式属性3.3.操作类名(className) 操作CSS3.4.操作表单元素属性3.5.自定…

【深入理解设计模式】建造者设计模式

建造者设计模式 建造者设计模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;旨在通过将复杂对象的构建过程拆分成多个简单的步骤&#xff0c;使得相同的构建过程可以创建不同的表示。该模式允许您使用相同的构建过程来创建不同的对象表示。 概述…

Leetcode刷题笔记题解(C++):6. Z 字形变换

思路&#xff1a;遍历时候需要更新步进长度 到达0行的时候步进长度为1&#xff1b;到达最后一行numRows-1行的时候步进长度为-1&#xff1b;代码如下所示&#xff1a; class Solution { public:string convert(string s, int numRows) {//如果字符串长度为1或者所给行数为1 …

[c++] char * 和 std::string

1 char * 和 std::string 的区别 char * 字符串是常量字符串&#xff0c;不能修改&#xff1b;std::string 指向的字符串可以修改 实例代码如下图所示&#xff0c;s1 和 s2 均是常量字符串&#xff0c;字符串常量保存在只读数据区&#xff0c;是只读的&#xff0c;不能写&…

Unity类银河恶魔城学习记录7-9 P75 Saw spin sword源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Sword_Skill_Controller.cs using System.Collections; using System.Col…

QT信号槽实现分析

1.宏定义 qt中引入了MOC来反射&#xff0c;编译阶段变成 MOC–>预处理–>编译–>汇编–>链接 1-1、Q_OBJECT 这个宏定义了一系列代码&#xff0c;包括元对象和处理的函数 #define Q_OBJECT \public: \QT_WARNING_PUSH \Q_OBJECT_NO_OVERRIDE_WARNING \static c…

设计模式(二)单例模式的七种写法

相关文章设计模式系列 面试的时候&#xff0c;问到许多年轻的Android开发他所会的设计模式是什么&#xff0c;基本上都会提到单例模式&#xff0c;但是对单例模式也是一知半解&#xff0c;在Android开发中我们经常会运用单例模式&#xff0c;所以我们还是要更了解单例模式才对…

汇编语言与接口技术实践——秒表

1. 设计要求 基于 51 开发板,利用键盘作为按键输入,将数码管作为显示输出,实现电子秒表。 功能要求: (1)计时精度达到百分之一秒; (2)能按键记录下5次时间并通过按键回看 (3)设置时间,实现倒计时,时间到,数码管闪烁 10 次,并激发蜂鸣器,可通过按键解除。 2. 设计思…

音视频技术-电脑连接调音台时交流声的产生与消除

当电脑&#xff08;笔记本/台式机&#xff09;声卡通过音频线与调音台&#xff08;或扩音机&#xff09;连接时&#xff0c;能听到“交流声”。有时很轻微&#xff0c;有时很明显&#xff0c;甚至干扰正常的演讲或发言。 很多时候&#xff0c;我们在台上演讲时&#xff0c;都会…

模拟、排序(归并排序)算法

模拟、排序算法 一、模拟例题1、错误票据题目信息思路题解 2、回文日期题目信息思路方法一&#xff1a;暴力做法方法二&#xff1a;优化解法 题解方法一&#xff1a;暴力求解方法二&#xff1a;优化解法 二、排序例题1、归并排序题目信息思路题解 一、模拟 例题 1、错误票据 …

springboot222学生网上选课系统的设计与实现

学生网上选课系统的设计与实现 摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统学生选课信息管理难度大&…

MDC500-16-ASEMI工业电机专用MDC500-16

编辑&#xff1a;ll MDC500-16-ASEMI工业电机专用MDC500-16 型号&#xff1a;MDC500-16 品牌&#xff1a;ASEMI 正向电流&#xff08;Id&#xff09;&#xff1a;500A 反向耐压&#xff08;VRRM&#xff09;&#xff1a;1600V 正向浪涌电流&#xff1a;600A 正向电压&a…

MATLAB Function转C代码实战

文章目录 前言1. 准备工作2. 使用MATLAB Coder2.1 确定输入输出的类型2.2 MATLAB Coder过程 3. 代码调整和优化4. 编译和测试5. 性能分析和优化结语 前言 在科学与工程领域&#xff0c;MATLAB&#xff08;Matrix Laboratory&#xff09;是一种广泛使用的高级技术计算软件&…

【C之·预处理器】

系列文章目录 文章目录 前言一、预处理指令1. #line的用法1.1 概述 2. #error2.1 概述 二、示例1. #line2. #error 总结 前言 C 预处理器不是编译器的组成部分&#xff0c;但是它是编译过程中一个单独的步骤。简言之&#xff0c;C 预处理器只不过是一个文本替换工具而已&#x…

从0到1入门C++编程——08 函数模板和类模板

文章目录 函数模板1.函数模板基本语法2.函数模板使用的注意事项3.函数模板案例——数组排序4.普通函数和函数模板的区别5.普通函数和函数模板的调用规则6.模板的局限性 类模板1.类模板2.类模板和函数模板的区别3.类模板中成员函数创建时机4.类模板对象做函数参数5.类模板与继承…

飞机订票系统

飞机订票系统 获取源码——》公主号&#xff1a;计算机专业毕设大全

Sora背后团队大揭秘!天才00后?

现在世界上最受关注的技术团队是哪一支&#xff1f; Sora 团队&#xff0c;已经来到聚光灯中心。 不仅项目负责人评论区被挤爆&#xff0c;成了&#x1d54f;最火“景点” 。 当 OpenAI 出手发布 Sora 之后&#xff0c;给人一种降维打击的感觉 —— 效果和之前的技术相比高出…

「哈哥赠书活动 - 48期」-『商业分析思维与实践:用数据分析解决商业问题宣传文案』

⭐️ 赠书 - 《商业分析思维与实践》 ⭐️ 内容简介 本书以业务为导向&#xff0c;详细地讲解了如何通过大数据分析来解决商业问题。其目的在于运用大数据分析思维&#xff0c;帮助读者把学术知识应用于真实的业务场景&#xff0c;解决实际的业务问题。本书基于业务问题&#x…

应急响应实战笔记03权限维持篇(3)

0x00 前言 攻击者在获取服务器权限后&#xff0c;会通过一些技巧来隐藏自己的踪迹和后门文件&#xff0c;本文介绍Linux下的几种隐藏技术。 0x01 隐藏文件 Linux 下创建一个隐藏文件&#xff1a;touch .test.txt touch 命令可以创建一个文件&#xff0c;文件名前面加一个 点…