vue3+ts+java使用WebSocket传输数据

news2025/1/11 21:46:56

一、环境

系统:win11

IDE:vscode

框架:electron22.0.0+vite2+vue3+typescript4.8.4+springboot2.2.5+jdk1.8

二、websocket介绍

2.1 由来

        WebSocket未出现之前,浏览器和服务器之间的通信是通过Web的poll技术进行通信,就是浏览器不停的对服务器主动发动请求,每发起一次新的HTTP请求,就是开启一次新的TCP链接,HTTP协议本身就是一种开销非常大的协议,所以这种方式效率低下。于是就出现了WebSocket协议。

        下面是采用poll方式的代码示例:

setInterval(() => {
  // 查询注册机列表
  getRegisterInfo().then(res => {
     isHost.value = store.state.onHost;   
  }).catch(err => {
     console.log('getComputerList err:', err);
  });
}, 1000);

为了页面及时更新,会像服务器产生大量的请求,造成资源浪费。

2.2 WebSocket通信过程

        WebSocket是一种完全不同于HTTP的协议,但是它需要通过HTTP协议的GET请求,将HTTP协议升级为WebSocket协议。升级的过程被称为握手(handshake)。当浏览器和服务器握手成功后,则可以开始根据WebSocket定义的通信帧格式开始通信了。WebSocket协议的通信帧也分为控制数据帧和普通数据帧,前者用于控制WebSocket链接状态,后者用于承载数据。

        握手过程就是将HTTP协议升级为WebSocket协议的过程。在HTTP的GET请求头部添加信息如下:

Upgrade: websocket      #规定必需的字段,其值必需为 websocket , 如果不是则握手失败;
Connection: Upgrade  #规定必需的字段,值必需为 Upgrade , 如果不是则握手失败;
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==    #必需字段,一个随机的字符串;
Sec-WebSocket-Protocol: chat, superchat   #可选字段,可以用于标识应用层的协议;
Sec-WebSocket-Version: 13  #必需字段,代表了 WebSocket 协议版本,值必需是 13 , 否则
握手失败;

当服务器端,成功验证了以上信息后,则会返回一个形如以下信息的响应:

HTTP/1.1 101 Switching Protocols   #101代表握手成功的状态码
Upgrade: websocket  #规定必需的字段,其值必需为 websocket , 如果不是则握手失败;
Connection: Upgrade #规定必需的字段,值必需为 Upgrade , 如果不是则握手失败;
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=  #规定必需的字段,该字段的值是通过固定字符串 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 加上请求中 Sec-WebSocket-Key 字段的值,然后再对其结果通过 SHA1 哈希算法求出的结果。
Sec-WebSocket-Protocol: chat  #对应于请求中的 Sec-WebSocket-Protocol 字段;

2.3 WebSocket 优缺点

        优点:

        1、使用资源少。创建连接后,数据叫唤的包头较少;

        2、能实现及时通信。长连接,实时通信;

        3、更好的二进制支持。能更好的处理二进制内容;

        4、支持拓展。用户可以拓展协议,实现部分自定义的子协议。

        缺点:

        1、使用WebSocket,长连接,会占用一定资源;

        2、浏览器品类多,支持程度不同,可能问题多;

        3、与poll相比,代码复杂度将上升,完全依赖于websocket,要多写逻辑对websocket状态进行监控,对开发者要求也会高一些。

       没有完美的事物,我们讨论优缺点的目的是它适合什么场景,在要求实时性较高的应用时,那么WebSocket会更适合。如果基本都是操作的应用,实时性要求很低,那么WebSocket使用的资源成本就是不合适的。

2.4 浏览器支持

      WebSocket - Web API 接口参考 | MDNWebSocket 对象提供了用于创建和管理 WebSocket 连接,以及可以通过该连接发送和接收数据的 API。icon-default.png?t=N7T8https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket以上是供参考的API接口,本文不做赘述,自己进入使用。

三、前端使用示例

文件名称

具体代码

/*
 * @Descripttion: 封装socket方法
 * @version:
 * @Date: 2021-08-06 11:14:39
 * @LastEditTime: 2021-10-26 14:06:34
 */
import { store } from "../store";
import { ElMessage } from "element-plus";
import { Base64 } from "js-base64";
import { updateComputerIsValid } from "/@/service/AppService";
import { localIp, playDutySound } from "../CommonUtil";
import { deal3004Procotol, deal3005Procotol, deal3006Procotol } from "/@/service/WebsocketService"; //业务代码

interface socket {
    websocket: any;
    connectURL: string;
    socket_open: boolean;
    hearbeat_timer: any;
    hearbeat_interval: number;
    is_reonnect: boolean;
    reconnect_count: number;
    reconnect_current: number;
    ronnect_number: number;
    reconnect_timer: any;
    reconnect_interval: number;
    // init: (receiveMessage: Function | null) => any;
    init: () => any;
    receive: (message: any) => void;
    heartbeat: () => void;
    send: (data: any, callback?: any) => void;
    close: () => void;
    reconnect: () => void;
    webSocketBack?: (message: any) => void;
}

const socket: socket = {
    websocket: null,
    connectURL: import.meta.env.VITE_WEBSOCKET_MONITOR_URL + localIp().replaceAll(".", ""),
    // 开启标识
    socket_open: false,
    // 心跳timer
    hearbeat_timer: null,
    // 心跳发送频率
    hearbeat_interval: 3000,
    // 是否自动重连
    is_reonnect: true,
    // 重连次数
    reconnect_count: 5000,
    // 已发起重连次数
    reconnect_current: 1,
    // 网络错误提示此时
    ronnect_number: 0,
    // 重连timer
    reconnect_timer: null,
    // 重连频率 不能设置的太小,否则会出现一次重连未返回的时候,下一次又开始重连
    reconnect_interval: 6000,

    // init: (receiveMessage: Function | null) => {
    init: () => {
        if (!("WebSocket" in window)) {
            // if (!("WebSocket" in window)) {
            ElMessage.warning("浏览器不支持WebSocket");
            return null;
        }
        // 已经创建过连接不再重复创建
        if (socket.websocket) {
            return socket.websocket;
        }

        socket.websocket = new WebSocket(socket.connectURL);
        socket.websocket.onmessage = (e: any) => {
            // if (receiveMessage) {
            //     receiveMessage(e);
            // }
            if (socket.webSocketBack) {
                socket.webSocketBack(e);
            }
        };

        socket.websocket.onclose = (e: any) => {
            console.log("websocket--关闭", socket.reconnect_current,e);
            if (socket.hearbeat_timer) {
                clearInterval(socket.hearbeat_timer);
            }
            //业务代码- 置位为1
            updateComputerIsValid(localIp(), 1);
            socket.socket_open = false;

            // 需要重新连接
            if (socket.is_reonnect) {
                console.log("websocket--需要重新连接", socket.is_reonnect,socket.reconnect_interval);
                socket.reconnect_timer = setTimeout(() => {
                    console.log("websocket--重连", socket.reconnect_current);
                    // 超过重连次数
                    if (
                        socket.reconnect_current > socket.reconnect_count &&
                        socket.reconnect_count > -1
                    ) {
                        console.log("websocket--超过重连次数");
                        clearTimeout(socket.reconnect_timer);
                        socket.is_reonnect = false;
                        return;
                    }

                    // 记录重连次数
                    socket.reconnect_current++;
                    //清除 socket.websocket
                    socket.websocket = null;
                    socket.reconnect();
                }, socket.reconnect_interval);
            }
        };

        // 连接成功
        socket.websocket.onopen = function () {
            console.log("websocket--连接成功");
            //业务代码
            updateComputerIsValid(localIp(), 0);
            socket.socket_open = true;
            socket.is_reonnect = true;
            // 开启心跳
            socket.heartbeat();
        };

        // 连接发生错误
        socket.websocket.onerror = function () {
            console.log("websocket--发生错误!关闭执行重连");
            socket.websocket.onclose();
        };
    },

    send: (data, callback = null) => {
        // 开启状态直接发送
        if (socket.websocket.readyState === socket.websocket.OPEN) {
            socket.websocket.send(JSON.stringify(data));
            if (callback) {
                callback();
            }

            // 正在开启状态,则等待1s后重新调用
        } else {
            clearInterval(socket.hearbeat_timer);
            if (socket.ronnect_number < 1) {
                // ElMessage({
                // 	type: 'error',
                // 	message: i18n.global.t('chat.unopen'),
                // 	duration: 0,
                // })
                console.log("服务关闭了!");
            }
            socket.ronnect_number++;
        }
    },

    receive: (message: any) => {
        let params = Base64.decode(JSON.parse(message.data).data);
        params = JSON.parse(params);
        return params;
    },

    heartbeat: () => {
        if (socket.hearbeat_timer) {
            clearInterval(socket.hearbeat_timer);
        }

        socket.hearbeat_timer = setInterval(() => {
            let diffMs = Number(new Date()) - Number(store.state.webSocketLastTime);
            console.log("websocket--上次间隔时间:", diffMs, "3秒以上才发送心跳包");
            if (diffMs > 0) {
                let data = {
                    // languageId: store.state.users.language,
                    content: "ping",
                };
                var sendDara = {
                    encryption_type: "base64",
                    data: Base64.encode(JSON.stringify(data)),
                };
                socket.send(sendDara);
                store.commit("setWebSocketLastTime", new Date());
                console.log(
                    "websocket--心跳发送",
                    sendDara,
                    "更新时间:",
                    store.state.webSocketLastTime
                );
            }
        }, socket.hearbeat_interval);
    },

    close: () => {
        clearInterval(socket.hearbeat_timer);
        socket.is_reonnect = false;
        socket.websocket.onclose();
    },

    /**
     * 重新连接
     */
    reconnect: () => {
        //websocket存在且不想重连的时候
        if (!socket.is_reonnect) {
        // if (socket.websocket && !socket.is_reonnect) {
            console.log("websocket--存在但是不需要重连的时候,关闭", socket.websocket, socket.is_reonnect);
            socket.close();
        }
        
        socket.init();
    },

    /**
     * 业务代码--数据处理 
     * @param backMessage
     */
    webSocketBack(backMessage: any) {
        store.commit("setWebSocketLastTime", new Date());
        console.log(
            "websocket-接受到的信息" + JSON.stringify(backMessage),
            "更新的时间:",
            store.state.webSocketLastTime
        );
        const wsData = backMessage.data.split("|");
        const wsDataCode = backMessage.data.split("|")[0];
        // 零位是协议号
        switch (wsDataCode) {
            // 值班机获取 提醒间隔时间 后的处理
            case "3002": {
                console.log("收到ws:3002: " + JSON.stringify(wsData));
                const setHost = wsData[1];
                store.commit("setDutyConfirmTime", Number(wsData[2]));
                if (setHost === "0") {
                    store.commit("setLocalComputerDutyState", 0);
                    store.commit("setOnDutyState", 0);
                } else {
                    store.commit("setLocalComputerDutyState", 1);
                    store.commit("setOnDutyState", 1);
                }
                break;
            }
            case "3003": {
                console.log("收到ws:3003", wsDataCode);
                if (wsData[1] === "0") {
                    playDutySound();
                    if (store.state.onDutyState === 0) {
                    } else if (store.state.onDutyState === 1) {、
                        playDutySound();
                        store.commit("setOnDutyState", true);
                    }
                } else if (wsData[1] === "1") {
                    store.commit("setOnDutyState", false);
                }
                break;
            }
            case "3004": {
                //更新store中的数据
                deal3004Procotol(wsData);
                break;
            }
            case "3005": {
                //更新store中的数据
                deal3005Procotol(wsData);
                break;
            }
            case "3006": {
                //更新store中的数据
                deal3006Procotol(wsData);
                break;
            }
        }
    },
};

export default socket;

其中业务代码请不用关注,自己实现自己的业务逻辑即可。

1001错误

对于重连时间的设置,如果设置的时间太短,会出现反复1001错误(The WebSocket session [] timeout expired)关闭再重连的现象:

把服务端关闭后

每次错误返回中间有两次重连操作,所以调整了重连间隔时间,错误消失,推论:一次重连结果还未出来的时候,又发起了地址一样的连接请求,造成冲突,会关闭上次连接,这次关闭会引发上次连接的重连,这就造成了反复重连。目前我采用的是拉长重连时间,比较简单,可以尝试通过判断连接状态来阻止一次连接没完成之前再次连接。

流程图

启动连接

//APP.VUE
import socket from "/@/utils/websocket";

onMounted(async () => {
  socket.init();
});

四、后端服务

引入依赖包

<dependency>
    <!-- websocket -->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

客户端ip获取:

在mainApplication上添加下面注解:

@ServletComponentScan("**.**.filter")  //防止 @WebListener 无效
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@javax.servlet.annotation.WebFilter(filterName = "sessionFilter",urlPatterns = "/*")
@Order(1)
public class WebFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req= (HttpServletRequest) servletRequest;
        req.getSession().setAttribute("ip",req.getRemoteHost());
        filterChain.doFilter(servletRequest,servletResponse);
    }
}

WebSocket配置类

在这里也做了IP的获取

@Configuration
public class WebSocketConfig extends ServerEndpointConfig.Configurator {
    /**
     * 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }


    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {

        Map<String, Object> attributes = sec.getUserProperties();
        HttpSession session = (HttpSession) request.getHttpSession();
        if (session != null) {
            attributes.put(GlobalContants.IP_ADDR, session.getAttribute("ip"));
            Enumeration<String> names = session.getAttributeNames();
            while (names.hasMoreElements()) {
                String name = names.nextElement();
                attributes.put(name, session.getAttribute(name));
            }
        }
    }
}

Websocket接收

import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
import com.deyou.cabin.monitor.common.GlobalContants;
import com.deyou.cabin.monitor.common.GlobalParams;
import com.deyou.cabin.monitor.common.utils.AssembleDownProtocolUtils;
import com.deyou.cabin.monitor.common.utils.CommonServeUtils;
import com.deyou.cabin.monitor.config.WebSocketConfig;
import com.deyou.cabin.monitor.model.WebSocketModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


@Slf4j
@Component
//@RequiredArgsConstructor
@ServerEndpoint(value = "/websocket/monitor/{code}",configurator = WebSocketConfig.class)
public class WebsocketController {

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session,@PathParam(value = "code") String code) {
        try
        {
            session.setMaxIdleTimeout(30000);
        }
        catch (Exception e)
        {
            log.error(e.getMessage(),e);
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session) {
        try
        {
            log.info("有一连接关闭:{},当前在线人数为:{}", session.getId(), 
        }
        catch (Exception e)
        {
            log.error(e.getMessage(),e);
        }
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message
     *            
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        try
        {
            log.info("服务端收到客户端[{}]的消息:{}", session.getId(), message);
        }
        catch (Exception ex)
        {
            log.error(ex.getMessage(),ex);
        }
        
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("websocket发生错误:" + session.getId() + "---" + error.getMessage(),error);
    }

    public void sendMessageToAll(String message, Session fromSession) {
        try
        {
            //GlobalParams.webSocketModelMap是全局变量 ConcurrentHashMap<String, WebSocketModel> webSocketModelMap
            for (Map.Entry<String, WebSocketModel> sessionEntry : GlobalParams.webSocketModelMap.entrySet()) {
                Session toSession = sessionEntry.getValue().getSession();
                // 排除掉自己
                if (!fromSession.getId().equals(toSession.getId())) {
                    log.info("服务端给客户端[{}][{}]发送消息{}", toSession.getId(),
                            sessionEntry.getValue().getWebSocketCode(), message);
                    sendMessToOne(message,toSession);
                }
            }
        }
        catch (Exception e)
        {
            log.error(e.getMessage(),e);
        }

    }

    public void sendMessageToAll(String message) {
        try {
            //GlobalParams.webSocketModelMap是全局变量 ConcurrentHashMap<String, WebSocketModel> webSocketModelMap
            for (Map.Entry<String, WebSocketModel> sessionEntry : GlobalParams.webSocketModelMap.entrySet()) {
                Session toSession = sessionEntry.getValue().getSession();
                log.info("服务端给客户端[{}][{}]发送消息{}", toSession.getId(), sessionEntry.getValue().getWebSocketCode(), message);
                sendMessToOne(message, toSession);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    public void sendMessToOne(String message, Session toSession) {
        try {
            // 尝试过锁住方法,还是不行,这里锁住webSocketMap,让多线程,访问不同对象,也能同步
            synchronized(GlobalParams.webSocketModelMap){
                String toId = toSession.getId();
                if (StringUtils.isNotBlank(toId) && GlobalParams.webSocketModelMap.containsKey(toId)) {
                    GlobalParams.webSocketModelMap.get(toId).getSession().getBasicRemote().sendText(message);
                }
            }
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败,"+e.getMessage(),e);
        }
    }

}

其中,synchronized(GlobalParams.webSocketModelMap)中GlobalParams.webSocketModelMap是我记录当前在线的websocket的信息。上边代码的注释中已经写了,这个锁的目的是为了解决websocket服务端下发时出现的错误“The remote endpoint was in state [STREAM_WRITING] which is an invalid state for called method”的错误,问题的引发场景和分析个人记录如下: 

1.因为在 @OnMessage中,我有两个方法同时使用了session,导致session多线程不安全,发生的频次少都可能不出现这个问题!

2.JSON.toJSONString(GlobalParams.webSocketModelMap) 其中带有session,会引发这个问题 解决办法:加异步锁,但是需要锁定 ConcurrentHashMap<String, WebSocketModel>。

使用

@Resource
private WebsocketController websocketService;
try{
    websocketService.sendMessToOne(sendMes, toSession);
}catch (Exception e){
    log.error(e.getMessage(),e);
}

5、结束

连接地址:ws://IP:PORT/websocket/monitor/{code} ,其中code是你自己定义的值。


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

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

相关文章

牛客java训练题 day1

9.24 day1 Q 1. this 指针是用来干什么的&#xff1f; 2.基类和派生类分别是指什么&#xff1f; 3.为什么方法中不能写静态变量 4. 解释一下ASCII码和ANSI码和两者的区别 5.简述j ava.io java.sql java.awt java.rmi 分别是什么类型的包 6. 看下面一段代码&#xff1a;…

分类预测 | Matlab实现NGO-CNN-SVM北方苍鹰算法优化卷积支持向量机分类预测

分类预测 | Matlab实现NGO-CNN-SVM北方苍鹰算法优化卷积支持向量机分类预测 目录 分类预测 | Matlab实现NGO-CNN-SVM北方苍鹰算法优化卷积支持向量机分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现NGO-CNN-SVM北方苍鹰算法优化卷积支持向量机分类预…

安全防御第二次作业

1. 防火墙支持那些NAT技术&#xff0c;主要应用场景是什么&#xff1f; 防火墙支持几乎所有的NAT技术&#xff0c;包括源NAT、目标NAT、双向NAT等&#xff0c;主要应用场景是保护内部网络免受外部网络的攻击 NAT技术可以将IP数据报文头中的IP地址转换为另一个IP地址&#xff…

暴力递归转动态规划(七)

题目 LeetCode原题-最长回文子序列 给你一个字符串 s &#xff0c;找出其中最长的回文子序列&#xff0c;并返回该序列的长度。 子序列定义为&#xff1a;不改变剩余字符顺序的情况下&#xff0c;删除某些字符或者不删除任何字符形成的一个序列。 示例 1&#xff1a; 输入&a…

【【萌新的FPGA学习之按键控制LED实验】】

按键控制LED实验 在写这篇文章之前我必须对我的错误表示深刻的道歉 因为我之前的文章自己也是边看边学给大家带来了大的困扰 抱歉抱歉 我们这里讲述一下综合和仿真的关系 其实我们更多的是应该关注仿真下得到的波形情况 然后分析 对于综合&#xff0c;综合的最大的目的还是看功…

计算机等级考试—信息安全三级真题二

目录 一、单选题 二、填空题 三、综合题 一、单选题

数据结构的奇妙世界:实用算法与实际应用

文章目录 数据结构和算法的基本概念数据结构数组链表栈队列树图 算法 常见的数据结构和算法排序算法快速排序示例 数据结构的应用数据库管理系统图像处理网络路由 数据结构和算法的性能分析时间复杂度空间复杂度 如何更好地编写代码避免常见错误结论 &#x1f389;欢迎来到数据…

Qt地铁智慧换乘系统浅学( 三 )最少路径和最少换乘实现

本算法全都基于广度优先 概念最短路径实现所用容器算法思路 最少换乘实现所需容器算法思路 成果展示代码实现判断是最短路径还是最少换乘最短路径代码实现最少换乘代码实现根据所得List画出线路 ui界面的维护&#xff08;前提条件&#xff09;界面初始化combox控件建立槽函数 概…

把Eclipse整个文件夹添加到Microsoft Defender的排除项中

一.原因&#xff1a; Windows 10卫士显著降低了Eclipse的速度&#xff0c;原因是Windows 10卫士扫描JAR文件。这个问题已经报告给微软了。在此之前&#xff0c;解决此问题的一个方法是将Eclipse根目录添加到Windows 10 Defender的排除列表中&#xff0c;详细步骤在这里共享。 …

前端JavaScript入门到精通,javascript核心进阶ES6语法、API、js高级等基础知识和实战 —— JS基础(五)

接受自己原本的样子&#xff0c; 比努力扮演另一个轻松多了。 思维导图 对象 什么是对象 对象使用 遍历对象 索引号是字符串型&#xff0c;不推荐遍历数组。 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><me…

docker实现mysql主从复制(巨详细!!!)

docker实现mysql主从复制&#xff08;巨详细&#xff01;&#xff01;&#xff01;&#xff09; 新建主机服务容器实例3307进入/mydata/mysql-master/conf目录下新建my.cnf修改完配置后重启master实例进入mysql-master容器master容器实例内创建数据同步用户新建 服务器容器实例…

【论文阅读】内存数据库并发控制算法的实验研究

内存数据库并发控制算法的实验研究 原文链接jos.org.cn/jos/article/pdf/6454 摘要 并发控制算法的基本思想归纳为"先定序后检验”&#xff0c;基于该思想对现有各类并发控制算法进行 了重新描述和分类总结&#xff0c;于在开源内存型分布式事务测试床 3TS 上的实际对比实…

Tune-A-Video论文阅读

论文链接&#xff1a;Tune-A-Video: One-Shot Tuning of Image Diffusion Models for Text-to-Video Generation 文章目录 摘要引言相关工作文生图扩散模型文本到视频生成模型文本驱动的视频编辑从单个视频生成 方法前提DDPMsLDMs 网络膨胀微调和推理模型微调基于DDIM inversio…

动手学深度学习(pytorch版)第二章-2.3线性代数Note-linear-algebra

类型 标量&#xff1a;仅包含一个数值被称为标量 向量&#xff1a;向量可以被视为标量值组成的列表 矩阵&#xff1a;正如向量将标量从零阶推广到一阶&#xff0c;矩阵将向量从一阶推广到二阶。 A torch.arange(20).reshape(5, 4) A.T //转置 张量&#xff1a;是描述具有…

[36c3 2019]includer

[36c3 2019]includer 题目描述&#xff1a;Just sitting here and waiting for PHP 8.0 (lolphp). 首先来了解一下临时文件包含之PHP - compress.zlib:// 在 php-src 里可以找到和 compress.zlib:// 有关的代码 | code 注意到 STREAM_WILL_CAST&#xff0c;涉及到 cast 经常…

企业微信-通用开发参数回调设置

公司业务需要开发企业微信&#xff0c;注册三方服务商审核通过后&#xff0c; 开始配置开发信息。本篇中记录在调试url验证中遇到错误及解决方式。 目录 准备工作 下载php加解密库 下载文件说明 设置白名单 设置路径 参数说明 设置ip 回调处理 回调类型&#xff1a; …

【C++】布隆过滤器简单操纵模拟以及常见题目

&#x1f30f;博客主页&#xff1a; 主页 &#x1f516;系列专栏&#xff1a; C ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ &#x1f60d;期待与大家一起进步&#xff01; 文章目录 前言一、求下标仿函数的建议二、布隆过滤器代码面试题1.近似算法&#xff1a;2.精确算…

Leetcode 409. 最长回文串

文章目录 题目代码&#xff08;9.24 首刷自解&#xff09; 题目 Leetcode 409. 最长回文串 代码&#xff08;9.24 首刷自解&#xff09; class Solution { public:int longestPalindrome(string s) {unordered_map<char, int> mp;for(char c : s) mp[c];int res 0;int…

【算法思想-排序】排序数组-力扣 912 题

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…