WebSocket+Http实现功能加成

news2024/9/22 21:18:42

WebSocket+Http实现功能加成

在这里插入图片描述

前言

首先,WebSocket和HTTP是两种不同的协议,它们在设计和用途上有一些显著的区别。以下是它们的主要特点和区别:

HTTP (HyperText Transfer Protocol):

  1. 请求-响应模型: HTTP 是基于请求-响应模型的协议,客户端发送请求,服务器返回响应。这是一个单向通信的模式。

  2. 无状态: HTTP 是无状态的协议,每个请求都是独立的,服务器不会记住之前的请求状态。为了维护状态,通常使用会话(Session)和 Cookie。

  3. 连接短暂: 每个请求都需要建立一个新的连接,然后在响应后关闭。这种短暂的连接模型适用于传统的网页浏览,但对于实时通信则显得不够高效。

  4. 端口: 默认使用端口80进行通信(HTTPS使用端口443)。

WebSocket:

  1. 双向通信: WebSocket 提供全双工通信,允许在客户端和服务器之间建立持久性的双向连接,实现实时数据传输。

  2. 状态: WebSocket 连接是持久性的,服务器和客户端之间可以保持状态。这减少了每次通信时的开销,使其适用于需要频繁交换数据的实时应用。

  3. 协议升级: WebSocket 连接通常通过HTTP协议的升级头部进行初始化,然后升级到WebSocket连接。这样的设计允许在HTTP和WebSocket之间平稳切换,同时在需要时实现更高级的协议升级。

  4. 端口: 默认使用端口80进行非安全通信,使用端口443进行安全通信。

  5. 低开销: 相比于HTTP轮询或长轮询,WebSocket 通信的开销较低,因为它减少了头部信息的传输,同时避免了不必要的连接和断开。

HTTP适用于传统的请求-响应模型,而WebSocket适用于需要实时、双向通信的应用场景,如在线游戏、聊天应用和实时协作工具。在某些情况下,它们可以结合使用,以充分发挥各自的优势。

代码实现

在这里,我们首先确定一个事情,就是这个我们以若依为主要的参考,在若依的基础上进行演示和操作,所以,对于若依这套架子有成见的同志请移步!!我们先创建一个信号量相关处理的工具类,作为辅助工具!

这段 Java 代码是一个用于处理信号量(Semaphore)的工具类,其中包含了获取信号量和释放信号量的方法。信号量是一种用于控制同时访问特定资源的线程数的同步工具。

package com.ruoyi.framework.websocket;

import java.util.concurrent.Semaphore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 信号量相关处理
 * 
 * @author ruoyi
 */
public class SemaphoreUtils
{
    /**
     * SemaphoreUtils 日志控制器
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(SemaphoreUtils.class);

    /**
     * 获取信号量
     * 
     * @param semaphore
     * @return
     */
    public static boolean tryAcquire(Semaphore semaphore)
    {
        boolean flag = false;

        try
        {
            // 尝试获取信号量,如果成功返回 true,否则返回 false
            flag = semaphore.tryAcquire();
        }
        catch (Exception e)
        {
            // 捕获异常并记录日志
            LOGGER.error("获取信号量异常", e);
        }

        return flag;
    }

    /**
     * 释放信号量
     * 
     * @param semaphore
     */
    public static void release(Semaphore semaphore)
    {
        try
        {
            // 释放信号量,增加可用的许可数
            semaphore.release();
        }
        catch (Exception e)
        {
            // 捕获异常并记录日志
            LOGGER.error("释放信号量异常", e);
        }
    }
}

解释每个部分的功能:

  1. tryAcquire(Semaphore semaphore) 方法:该方法尝试从信号量中获取一个许可。如果成功获取许可,返回 true;如果无法获取许可,返回 false。在获取信号量时,可能会抛出异常,例如在等待获取信号量的过程中发生中断或超时,因此在方法内捕获异常并记录日志。

  2. release(Semaphore semaphore) 方法:该方法释放一个许可到信号量中,增加信号量的可用许可数。同样,可能会在释放信号量时发生异常,捕获异常并记录日志。

这样的工具类通常用于协调多个线程对共享资源的访问,通过信号量可以限制同时访问某个资源的线程数量,以避免竞争和提高系统的稳定性。在这个类中,异常处理的目的是确保即使在获取或释放信号量的过程中发生异常,也能够进行适当的处理并记录相关信息。

然后呢,我们来编写一个websocket的配置文件,内容很简单,如下:

package com.ruoyi.framework.websocket;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * websocket 配置
 * 
 * @author ruoyi
 */
@Configuration
public class WebSocketConfig
{
    @Bean
    public ServerEndpointExporter serverEndpointExporter()
    {
        return new ServerEndpointExporter();
    }
/************************************************自己增加的内容*******************************************************************/
    @Bean
    public ServletServerContainerFactoryBean createWebSocketContainer() {
        ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
        // 在此处设置bufferSize
        container.setMaxTextMessageBufferSize(5120000);
        container.setMaxBinaryMessageBufferSize(5120000);
        container.setMaxSessionIdleTimeout(15 * 60000L);
        return container;
    }
}

这是一个WebSocket配置类,用于配置WebSocket相关的参数和组件。以下是对每个部分的详细介绍:

  1. @Configuration 注解:

    • 表示这是一个Spring配置类,用于配置WebSocket相关的组件。
  2. @Bean 方法 - serverEndpointExporter:

    • 创建并返回一个ServerEndpointExporter对象。
    • ServerEndpointExporter是Spring提供的用于注册和管理WebSocket端点的Bean,它会在Spring容器中查找所有使用@ServerEndpoint注解的WebSocket端点并注册它们。
    • 这个Bean的存在使得WebSocket端点能够被正确地注册并且可以被使用。
  3. @Bean 方法 - createWebSocketContainer:

    • 创建并返回一个ServletServerContainerFactoryBean对象。
    • ServletServerContainerFactoryBean是Spring提供的用于配置WebSocket容器的工厂Bean。通过配置它,可以设置WebSocket容器的一些参数。
    • 在这个方法中,设置了以下WebSocket容器的参数:
      • setMaxTextMessageBufferSize(5120000): 设置文本消息的最大缓冲区大小为5 MB。
      • setMaxBinaryMessageBufferSize(5120000): 设置二进制消息的最大缓冲区大小为5 MB。
      • setMaxSessionIdleTimeout(15 * 60000L): 设置会话的最大空闲时间为15分钟。

简而言之,这个WebSocket配置类使用Spring的Java配置方式,通过@Bean注解创建了两个Bean,分别是ServerEndpointExporterServletServerContainerFactoryBean。前者用于注册WebSocket端点,后者用于配置WebSocket容器的一些参数。这样,你的Spring Boot应用就能够正确地支持WebSocket了。

然后呢,就到了最主要的内容,我们需要写一个websocket服务类,里面有众多方法

package com.ruoyi.framework.websocket;

import java.util.concurrent.Semaphore;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * websocket 消息处理
 * 
 * @author ruoyi
 */
@Component
@ServerEndpoint("/websocket/message")
public class WebSocketServer
{
    /**
     * WebSocketServer 日志控制器
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServer.class);

    /**
     * 默认最多允许同时在线人数100
     */
    public static int socketMaxOnlineCount = 100;

    private static Semaphore socketSemaphore = new Semaphore(socketMaxOnlineCount);

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session) throws Exception
    {
        boolean semaphoreFlag = false;
        // 尝试获取信号量
        semaphoreFlag = SemaphoreUtils.tryAcquire(socketSemaphore);
        if (!semaphoreFlag)
        {
            // 未获取到信号量
            LOGGER.error("\n 当前在线人数超过限制数- {}", socketMaxOnlineCount);
            WebSocketUsers.sendMessageToUserByText(session, "当前在线人数超过限制数:" + socketMaxOnlineCount);
            session.close();
        }
        else
        {
            // 添加用户
            WebSocketUsers.put(session.getId(), session);
            LOGGER.info("\n 建立连接 - {}", session);
            LOGGER.info("\n 当前人数 - {}", WebSocketUsers.getUsers().size());
            WebSocketUsers.sendMessageToUserByText(session, "连接成功");
        }
    }

    /**
     * 连接关闭时处理
     */
    @OnClose
    public void onClose(Session session)
    {
        LOGGER.info("\n 关闭连接 - {}", session);
        // 移除用户
        WebSocketUsers.remove(session.getId());
        // 获取到信号量则需释放
        SemaphoreUtils.release(socketSemaphore);
    }

    /**
     * 抛出异常时处理
     */
    @OnError
    public void onError(Session session, Throwable exception) throws Exception
    {
        if (session.isOpen())
        {
            // 关闭连接
            session.close();
        }
        String sessionId = session.getId();
        LOGGER.info("\n 连接异常 - {}", sessionId);
        LOGGER.info("\n 异常信息 - {}", exception);
        // 移出用户
        WebSocketUsers.remove(sessionId);
        // 获取到信号量则需释放
        SemaphoreUtils.release(socketSemaphore);
    }

    /**
     * 服务器接收到客户端消息时调用的方法
     */
    @OnMessage
    public void onMessage(String message, Session session)
    {
        String msg = message.replace("你", "我").replace("吗", "");
        WebSocketUsers.sendMessageToUserByText(session, msg);
    }
}

这段代码是一个WebSocket服务器端的实现,用于处理与客户端的WebSocket通信。让我们逐步解释其关键部分:

  1. @Component 注解:

    • 表示将该类作为Spring组件进行管理,可以通过Spring的扫描机制自动识别并注册为bean。
  2. @ServerEndpoint("/websocket/message") 注解:

    • 将该类标记为WebSocket的端点,客户端可以通过访问 “/websocket/message” 路径来与服务器建立WebSocket连接,我们如果需要连接WebSocket,那么连接地址就是:ws:localhost:端口号/websocket/message,类似于http请求!
  3. @OnOpen 注解:

    • 标注一个方法,在WebSocket连接建立时触发。在这里,它用于处理连接建立成功后的逻辑。
    • 尝试获取信号量,如果成功,表示连接建立成功,会将该连接加入到用户列表中;否则,如果在线人数超过限制,会发送错误信息并关闭连接。
  4. @OnClose 注解:

    • 标注一个方法,在WebSocket连接关闭时触发。在这里,它用于处理连接关闭后的清理逻辑,包括移除用户并释放信号量。
  5. @OnError 注解:

    • 标注一个方法,在WebSocket发生异常时触发。在这里,它用于处理异常情况,关闭连接并进行相应的清理工作。
  6. @OnMessage 注解:

    • 标注一个方法,在服务器接收到客户端消息时触发。在这里,它将接收到的消息进行处理,例如将消息中的 “你” 替换为 “我”,去掉 “吗”,然后通过 WebSocketUsers.sendMessageToUserByText 方法将处理后的消息发送回客户端。

总体而言,这个类实现了WebSocket服务器的基本功能,包括连接的建立、关闭、异常处理以及消息的处理。同时,它通过信号量控制了最大允许同时在线人数,确保连接数不超过设定的限制。

代码也很简单,大家在网上也会找到类似的工具类,只不过若依是多加了一些封装

最后,就到了服务升级了,这也是若依特有的,我们一起看看:

package com.ruoyi.framework.websocket;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import javax.websocket.Session;

import com.alibaba.fastjson2.JSON;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * websocket 客户端用户集
 * 
 * @author ruoyi
 */
public class WebSocketUsers
{
    /**
     * WebSocketUsers 日志控制器
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketUsers.class);

    /**
     * 用户集
     */
    private static Map<String, Session> USERS = new ConcurrentHashMap<String, Session>();

    /**
     * 存储用户
     *
     * @param key 唯一键
     * @param session 用户信息
     */
    public static void put(String key, Session session)
    {
        USERS.put(key, session);
    }

    /**
     * 移除用户
     *
     * @param session 用户信息
     *
     * @return 移除结果
     */
    public static boolean remove(Session session)
    {
        String key = null;
        boolean flag = USERS.containsValue(session);
        if (flag)
        {
            Set<Map.Entry<String, Session>> entries = USERS.entrySet();
            for (Map.Entry<String, Session> entry : entries)
            {
                Session value = entry.getValue();
                if (value.equals(session))
                {
                    key = entry.getKey();
                    break;
                }
            }
        }
        else
        {
            return true;
        }
        return remove(key);
    }

    /**
     * 移出用户
     *
     * @param key 键
     */
    public static boolean remove(String key)
    {
        LOGGER.info("\n 正在移出用户 - {}", key);
        Session remove = USERS.remove(key);
        if (remove != null)
        {
            boolean containsValue = USERS.containsValue(remove);
            LOGGER.info("\n 移出结果 - {}", containsValue ? "失败" : "成功");
            return containsValue;
        }
        else
        {
            return true;
        }
    }

    /**
     * 获取在线用户列表
     *
     * @return 返回用户集合
     */
    public static Map<String, Session> getUsers()
    {
        return USERS;
    }

    /**
     * 群发消息文本消息
     *
     * @param message 消息内容
     */
    public static void sendMessageToUsersByText(String message)
    {
        Collection<Session> values = USERS.values();
        for (Session value : values)
        {
            sendMessageToUserByText(value, message);
        }
    }

    /**
     * 发送文本消息
     *
     * @param userName 自己的用户名
     * @param message 消息内容
     */
    public static void sendMessageToUserByText(Session session, String message)
    {
        if (session != null)
        {
            try
            {
                session.getBasicRemote().sendText(message);
            }
            catch (IOException e)
            {
                LOGGER.error("\n[发送消息异常]", e);
            }
        }
        else
        {
            LOGGER.info("\n[你已离线]");
        }
    }
/************************************************自己增加的内容***************************************************************/
    /**
     * 群发消息文本消息
     *
     * @param messages 消息内容
     */
    public static void sendMessageToUsers(List<String> messages, Collection<Session> values) {
        for (String message : messages) {
            for (Session value : values) {
                sendMessageToUserByText(value, message);
            }
        }
    }

    public static void sendMessageToUsersMap(List<Map<String, Object>> li, Collection<Session> values) {
        for (Map<String, Object> map : li) {
            for (Session value : values) {
                sendMessageToUserByText(value, JSON.toJSONString(map));
            }
        }
    }

    /**
     * 获取指定用户
     *
     * @param userIds 用户id
     * @return
     */
    public static Collection<Session> getSessionUserMap(List<Long> userIds) {
        Map<String, Session> sessionUserMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(userIds)) {
            List<String> newUserIds = userIds.stream().map(String::valueOf).collect(Collectors.toList());
            Map<String, Session> users = USERS;
            for (Iterator<Map.Entry<String, Session>> it = users.entrySet().iterator(); it.hasNext(); ) {
                Map.Entry<String, Session> item = it.next();
                String key = item.getKey();
                // 发送用户处理
                if (newUserIds.contains(key.substring(0, key.indexOf("_")))) {
                    sessionUserMap.put(key, item.getValue());
                }
            }
        }
        return sessionUserMap.values();
    }

    /**
     * 给用户发消息
     *
     * @param message 消息内容
     * @param userId  用户id
     */
    public static void sendMessageToUser(String message, Long userId) {
        List<Long> userList = new ArrayList<>();
        List<String> msgs = new ArrayList<>();
        // 添加发送对象
        userList.add(userId);
        // 添加发送内容
        msgs.add(message);
        Collection<Session> sessionUserMap = WebSocketUsers.getSessionUserMap(userList);
        WebSocketUsers.sendMessageToUsers(msgs, sessionUserMap);
    }
}

这段代码定义了一个用于管理WebSocket用户的工具类 WebSocketUsers

  1. put 方法:

    • 用于将用户信息存储到USERS集合中,其中key是用户的唯一标识,session是与用户连接关联的Session对象。
  2. remove 方法 (两个重载):

    • USERS集合中移除用户。一个版本是通过Session对象移除,另一个版本是通过用户的唯一键移除。
    • 首先检查是否包含给定的Session,然后根据情况找到对应的键,最后移除用户。
  3. getUsers 方法:

    • 返回当前在线用户的集合,即USERS集合。
  4. sendMessageToUsersByText 方法:

    • 用于向所有在线用户发送文本消息。遍历USERS集合中的每个用户的Session对象,并调用sendMessageToUserByText方法发送消息。
  5. sendMessageToUserByText 方法:

    • 向指定用户的Session发送文本消息。
    • 如果session不为null,使用session.getBasicRemote().sendText(message)发送文本消息;否则,记录用户已离线的信息。
  6. sendMessageToUsers 方法:

    • 向一组用户发送消息,接收一个包含消息的列表和一个包含Session对象的集合。
    • 遍历消息列表和Session集合,为每个用户的Session对象发送相应的消息。
  7. sendMessageToUsersMap 方法:

    • 向一组用户发送包含Map<String, Object>消息的列表。
    • 将每个Map对象转换为JSON格式的字符串,并使用sendMessageToUserByText方法发送给每个用户。
  8. getSessionUserMap 方法:

    • 根据给定的用户id列表,返回相应用户的Session对象集合。
    • 使用用户id列表过滤出匹配的Session对象,并将其存储在sessionUserMap中返回。
  9. sendMessageToUser 方法:

    • 向指定用户发送消息,接收消息内容和目标用户的id。
    • 创建包含目标用户id和消息内容的列表,然后通过getSessionUserMap方法获取匹配的Session对象集合,并使用sendMessageToUsers方法发送消息。

这些方法共同构成了一个WebSocket用户管理类,用于存储用户信息、发送消息,以及一些特定需求的消息发送,如向指定用户发送消息、向特定用户组发送消息等。

这样,我们就大概完成了整个代码逻辑,也不是非常复杂!

然后,我们就需要进行测试一波----------

ApiPost测试

在这里插入图片描述

在线工具测试 https://wstool.js.org/

在这里插入图片描述

控制台日志

在这里插入图片描述
然后,大家会问,怎么实现http功能加成,其实大家可以看到在WebSocketUsers有需要业务层的处理方法,其实这些就是供http请求调用的

如:
在这里插入图片描述
这就是专门提供给http调用的,实现给指定用户发送消息,如消息通知,或者是公告,审批消息提醒等————
完毕,感谢大家阅读!

所谓好运,所谓幸福,显然不是一种客观的程序,而是完全心灵的感受,是强烈的幸福感罢了。
——史铁生

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

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

相关文章

Leetcode刷题笔记题解(C++):面试题 08.07. 无重复字符串的排列组合

思路&#xff1a;因为字符之间互不相同&#xff0c;故使用全排列的方式去解题&#xff1b; 字符串长度为n&#xff0c;将第一个字母分别与后面每一个字母进行交换&#xff0c;生成n种不同的全排列&#xff1b;再用第二个元素与后面每一个元素进行交换&#xff0c;生成n - 1种不…

Spring Authorization Server Spring Security密码加密

文章目录 一、修改密码编码器二、效果三、注意点1. RegisteredClient2. UserDetailsService 一、修改密码编码器 以BCryptPasswordEncoder举例。 直接将其注册成PasswordEncoder 的Bean即可。 Beanpublic PasswordEncoder passwordEncoder() {// 密码为明文方式 // ret…

【PTA浙大版《C语言程序设计(第4版)》|编程题】习题7-3 判断上三角矩阵(附测试点)

目录 输入格式&#xff1a; 输出格式&#xff1a; 输入样例&#xff1a; 输出样例&#xff1a; 代码呈现 测试点 上三角矩阵指主对角线以下的元素都为0的矩阵&#xff1b;主对角线为从矩阵的左上角至右下角的连线。 本题要求编写程序&#xff0c;判断一个给定的方阵是否…

图论与图数据应用综述:从基础概念到知识图谱与图智能

目录 前言1 图论基础概念1.1 节点度1.2 度分布1.3 邻接矩阵 2 探索图的高级概念2.1 最短路径的关键性2.2 图的直径与平均路径的意义2.3 循环与路径类型的多样性 3 深入探讨图的广泛应用领域3.1 知识图谱的知识管理3.2 图智能在复杂决策中的应用3.3 图数据挖掘与分析的多领域应用…

【Linux】POSIX信号量基于环形队列的生产消费模型

需要云服务器等云产品来学习Linux的同学可以移步/–>腾讯云<–/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;优惠多多。&#xff08;联系我有折扣哦&#xff09; 文章目录 引入1. POSIX信号量1.1 信号量的概念1.2 信号量的使用1.2.1 信号量的初始化1.2.2信号…

AI助力农作物自动采摘,基于DETR(DEtection TRansformer)开发构建番茄采摘场景下番茄成熟度检测识别计数分析系统

去年十一那会无意间刷到一个视频展示的就是德国机械收割机非常高效自动化地24小时不间断地在超广阔的土地上采摘各种作物&#xff0c;专家设计出来了很多用于采摘不同农作物的大型机械&#xff0c;看着非常震撼&#xff0c;但是我们国内农业的发展还是相对比较滞后的&#xff0…

IOS破解软件安装教程

对于很多iOS用户而言&#xff0c;获取软件的途径显得较为单一&#xff0c;必须通过App Store进行下载安装。 这样的限制&#xff0c;时常让人羡慕安卓系统那些自由下载各类版本软件的便捷。 心中不禁生出疑问&#xff1a;难道iOS世界里&#xff0c;就不存在所谓的“破解版”软件…

Visual Studio 2010+C#实现信源编码

1. 要求 本文设计了一套界面系统&#xff0c;该系统能够实现以下功能&#xff1a; 克劳夫特不等式的计算&#xff0c;并且能够根据计算结果给出相应的信息。可通过用户输入的初始条件然后给出哈夫曼编码以及LZ编码&#xff0c;结果均通过对话框来显示哈夫曼编码结果包含相应的…

解密输入输出迷局:蓝桥杯与ACM中C++/C语言常见问题揭秘

关于C中的常见输入输出汇总 带空格的字符串&#xff1a; ​ 对于这种输入方式我们选择使用gets() 函数来进行输入&#xff0c;gets用于从标准输入&#xff08;通常是键盘&#xff09;读取一行文本并将其存储为字符串&#xff0c;直到遇到换行符&#xff08;‘\n’&#xff09…

Fink CDC数据同步(四)Mysql数据同步到Kafka

依赖项 将下列依赖包放在flink/lib flink-sql-connector-kafka-1.16.2 创建映射表 创建MySQL映射表 CREATE TABLE if not exists mysql_user (id int,name STRING,birth STRING,gender STRING,PRIMARY KEY (id) NOT ENFORCED ) WITH (connector mysql-cdc,hostn…

飞书上传图片

飞书上传图片 1. 概述1.1 访问凭证2. 上传图片获取image_key1. 概述 飞书开发文档上传图片: https://open.feishu.cn/document/server-docs/im-v1/image/create 上传图片接口,支持上传 JPEG、PNG、WEBP、GIF、TIFF、BMP、ICO格式图片。 在请求头上需要获取token(访问凭证) …

go消息队列RabbitMQ - 订阅模式-fanout

1、发布订阅 订阅模式&#xff0c;消息被路由投递给多个队列&#xff0c;一个消息被多个消费者获取。 1&#xff09; 可以有多个消费者 2&#xff09; 每个消费者有自己的queue&#xff08;队列&#xff09; 3&#xff09; 每个队列都要绑定到Exchange&#xff08;交换机&…

Linux系统安装(CentOS Vmware)

学习环境安装 VMware安装 VMware下载&安装 访问官网&#xff1a;https://www.vmware.com 在此处可以选择语言 点击China&#xff08;简体中文&#xff09; 点击产品&#xff0c;点击Workstation Pro 下滑&#xff0c;点击下载试用版 下滑找到Workstation 17 Pro for Wi…

ARP欺骗攻击利用之内网截取图片

Arp欺骗&#xff1a;目标ip的流量经过我的网卡&#xff0c;从网关出去。 Arp断网&#xff1a;目标ip的流量经过我的网卡 1. echo 1 >/proc/sys/net/ipv4/ip_forward 设置ip流量转发&#xff0c;不会出现断网现象 有时不能这样直接修改&#xff0c;还有另外一种方法 修…

基于华为云欧拉操作系统(HCE OS)容器化部署传统应用(Redis+Postgresql+Git+SpringBoot+Nginx)

写在前面 博文内容为 华为云欧拉操作系统入门级开发者认证(HCCDA – Huawei Cloud EulerOS)实验笔记整理认证地址&#xff1a;https://edu.huaweicloud.com/certificationindex/developer/9bf91efb086a448ab4331a2f53a4d3a1博文内容涉及一个传统 Springboot 应用HCE部署&#x…

使用QT编写一个简单QQ登录界面

widget.cpp #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//设置窗口标题this->setWindowTitle("QQ");//设置窗口图标this->setWindowIcon(…

uniapp的配置和使用

①安装环境和编辑器 注册小程序账号 微信开发者工具下载 uniapp 官网 HbuilderX 下载 首先先下载Hbuilder和微信开发者工具 &#xff08;都是傻瓜式安装&#xff09;&#xff0c;然后注册小程序账号&#xff1a; 拿到appid&#xff1a; ②简单通过demo使用微信开发者工具和…

Linux——进程池(管道)

经过了管道的介绍之后&#xff0c;我们可以实现了进程间通信&#xff0c;现在我就来简单介 绍一下管道的应用场景——进程池。1. 引入 在我们的编码过程中&#xff0c;不乏会听到&#xff0c;内存池&#xff0c;进程池&#xff0c;空间配置器等等名词&#xff0c;这些是用来干…

spring boot学习第十二篇:mybatis框架中调用存储过程控制事务性

1、MySQL方面&#xff0c;已经准备好了存储过程&#xff0c;参考&#xff1a;MYSQL存储过程&#xff08;含入参、出参&#xff09;-CSDN博客 2、pom.xml文件内容如下&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"…

zer0pts-2020-memo:由文件偏移处理不正确--引发的堆溢出

启动脚本 #!/bin/sh qemu-system-x86_64 \-m 256M \-kernel ./bzImage \-initrd ./rootfs.cpio \-append "root/dev/ram rw consolettyS0 oopspanic panic1 kaslr quiet" \-cpu kvm64,smep,smap \-monitor /dev/null \-nographic -enable-kvm/ # dmesg | grep page …