基于铜锁构建Web在线加密工具库

news2025/1/13 11:45:52

基于铜锁构建Web在线加密工具库

搭建运行环境

实验⼿册中的实验都是以 dockerdocker-compose 环境为主,基于 Ubuntu 20.04 容器镜像。

初始化项目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-doMrXRdM-1682067005381)(img.png)]

首先利用 IDE 创建一个 tongsuo_web 的空项目,接下来我们所有的文件都会创建在该项目中,我们首先构建运行环境,整个环境都是由 Dockerfile 进行构建,然后使用 docker-compose.yml 进行编排,使得宿主机不用进行环境依赖安装,实验完也可以快速删除环境,不对宿主机造成过多影响。

创建sources.list

因为 ubuntu 的默认 apt 源是比较慢的,对于我们实验会造成过慢,所以这里提前准备了 apt 源,在项目里新建 sources.list 文件,并将如下内容写入到文件中,下文就会使用到该配置

deb http://repo.huaweicloud.com/ubuntu/ focal main restricted universe multiverse
deb-src http://repo.huaweicloud.com/ubuntu/ focal main restricted universe multiverse
deb http://repo.huaweicloud.com/ubuntu/ focal-security main restricted universe multiverse
#deb-src http://repo.huaweicloud.com/ubuntu/ focal-security main restricted universe multiverse
deb http://repo.huaweicloud.com/ubuntu/ focal-updates main restricted universe multiverse
#deb-src http://repo.huaweicloud.com/ubuntu/ focal-updates main restricted universe multiverse
deb http://repo.huaweicloud.com/ubuntu/ focal-proposed main restricted universe multiverse
#deb-src http://repo.huaweicloud.com/ubuntu/ focal-proposed main restricted universe multiverse
deb http://repo.huaweicloud.com/ubuntu/ focal-backports main restricted universe multiverse
#deb-src http://repo.huaweicloud.com/ubuntu/ focal-backports main restricted universe multiverse

创建Dockerfile

在项目中首先创建 Dockerfile 文件,并把以下内容写入到文件中

FROM ubuntu:20.04
WORKDIR "/application"

ADD sources.list /etc/apt/

RUN apt-get update \
    && apt-get -y install git make gcc python3.7 python3-pip \
    && git config --global http.sslverify false \
    && python3 --version \
    && pip3 --version

RUN git clone https://atomgit.com/tongsuo/Tongsuo.git \
     && cd Tongsuo \
     && ./config --prefix=/opt/tongsuo enable-ntls enable-ssl-trace -Wl,-rpath,/opt/tongsuo/lib64 --debug \
    && make -j \
    && make install \
    && /opt/tongsuo/bin/tongsuo version

这是一个基于 ubuntu:20.04 的环境,他在构建的过程中替换了 apt 的源,并且将 gccmakepythongitpip 等环境所需工具进行了安装;通过 git 将铜锁的仓库克隆到容器中并进行编译,使得环境中拥有了铜锁。

通过docker-compose进行dockerfile构建

在项目中新建 docker-compose.yml 文件然后指定当前目录下的 Dockerfile

version: '3.1'
services:
    tongsuo:
      build:
        context: .
      working_dir: /application
      volumes:
          - '.:/application'
      ports:
        - "5000:5000"
      tty: true
      stdin_open: true

最终项目文件如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VBjqQLCR-1682067005382)(img_1.png)]

  • 创建环境
docker-compose up -d

在这里插入图片描述

出现下图输出即环境创建成功:

在这里插入图片描述

因为我们需要使用到 PythonFlask 作为 Web 框架,所以我们需要先进容器进行安装,命令如下

docker-compose exec -it tongsuo bash
pip3 install flask

安装完成后我们就可以来创建 Web Api

基于铜锁构建API

对铜锁SDK能力进行封装

新建一个名为 tongsuopackage

在这里插入图片描述

创建一个 tools.py,我们将铜锁SDK提供的 sm2sm3sm4 能力进行封装,相关函数如下:

import subprocess


# SM4-CBC加密
def sm4_cbc_encrypt(plaintext: str, key: str):
    command = 'echo ' + plaintext + ' | /opt/tongsuo/bin/tongsuo enc -K ' + key + ' -e -sm4-cbc ' \
                                                                                  '-iv 1fb2d42fb36e2e88a220b04f2e49aa13 -nosalt -base64',
    return shell(command)


# SM4-CBC解密
def sm4_cbc_decrypt(ciphertext: str, key: str):
    command = 'echo ' + ciphertext + '| /opt/tongsuo/bin/tongsuo enc -K '+key+' -d -sm4-cbc ' \
                                     '-iv 1fb2d42fb36e2e88a220b04f2e49aa13 -nosalt -base64'
    return shell(command)


# sm3杂凑算法
def sm3_dgst(ciphertext: str):
    command = 'echo -n ' + ciphertext + ' | /opt/tongsuo/bin/tongsuo dgst -sm3'
    return shell(command)


# sm2签名验证
def sm2_verify(sig_file: str, file_path: str):
    command = "/opt/tongsuo/bin/tongsuo dgst -sm3 -verify ./sm2pub.key -signature {} {}".format(sig_file, file_path)
    return shell(command)


# sm2 签名
def sm2_sign(file_path: str, sig_file: str):
    command = "/opt/tongsuo/bin/tongsuo dgst -sm3 -sign ./sm2.key -out {} {}".format(sig_file, file_path)
    return shell(command)


def shell(command):
    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    process.wait()

    # 获取命令的输出和错误信息
    output = process.stdout.read()
    error = process.stderr.read()

    # 将输出和错误信息解码为字符串
    output = output.decode(encoding="utf8")
    error = error.decode(encoding="utf8")

    # 返回命令的输出和错误信息
    result = {"output": output, "error": error}
    print(result)
    return result

main 文件中将封装好的函数能力通过 api 进行暴露

import random
from functools import wraps

from flask import Flask, send_file
from flask import render_template
from flask import request

from tongsuo.tools import sm3_dgst, sm4_cbc_encrypt, sm4_cbc_decrypt, sm2_verify, sm2_sign

app = Flask(__name__)


@app.route('/')
def index():
    return render_template('index.html')


def check_param(param_name):
    """
    装饰器,用于检查请求参数是否存在
    """

    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            param_value = request.form.get(param_name)
            if param_value is None:
                return f"Error: '{param_name}' parameter is missing", 400
            else:
                return func(param_value, *args, **kwargs)

        return wrapper

    return decorator


@app.route('/sm4_cbc_encrypt', methods=['POST'])
@check_param('msg')
@check_param('key')
def sm4_cbc_encrypt_endpoint(key, msg):
    return sm4_cbc_encrypt(msg, key)


@app.route('/sm4_cbc_decrypt', methods=['POST'])
@check_param('msg')
@check_param('key')
def sm4_cbc_decrypt_endpoint(key, msg):
    return sm4_cbc_decrypt(msg, key)


@app.route('/sm3_dgst', methods=['POST'])
@check_param('msg')
def sm3_dgst_endpoint(msg):
    return sm3_dgst(msg)


@app.route('/sm2_sign', methods=['POST'])
@check_param('path')
def sm2_sign_endpoint(path):
    sign_file = path + '_sign'
    sm2_sign(path, sign_file)
    return {'path': sign_file}


@app.route('/sm2_verify', methods=['POST'])
@check_param('file_path')
@check_param('sign_file_path')
def sm2_verify_endpoint(sign_file_path, file_path):
    return sm2_verify(sign_file_path, file_path)


@app.route('/upload', methods=['POST'])
def upload():
    file = request.files['file']
    random_num = str(random.randint(10000, 99999))
    filename = file.filename
    new_filename = random_num + '_' + filename
    save_path = './file/' + new_filename
    file.save(save_path)
    return {'path': save_path}


@app.route('/download', methods=['POST'])
@check_param('file_path')
def download_file(file_path):
    return send_file(file_path, as_attachment=True)


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)

我们还需要创建 file 目录,用来保存上传的文件,在我们进行 sm2签名和sm2验证的时候还需要公钥和私钥,我们在项目根目录中创建 sm2.key 和 sm2pub.key,内容如下:

  • sm2.key
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgSKhk+4xGyDI+IS2H
WVfFPDxh1qv5+wtrddaIsGNXGZihRANCAAQwqeNkWp7fiu1KZnuDkAucpM8piEzE
TL1ymrcrOBvv8mhNNkeb20asbWgFQI2zOrSM99/sXGn9rM2/usM/Mlca
-----END PRIVATE KEY-----
  • sm2pub.key
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEMKnjZFqe34rtSmZ7g5ALnKTPKYhM
xEy9cpq3Kzgb7/JoTTZHm9tGrG1oBUCNszq0jPff7Fxp/azNv7rDPzJXGg==
-----END PUBLIC KEY-----

这个时候我们的 API 就构建好了,可以从代码中看到,我们在 / 路由上还进行了前端页面的渲染,我们需要在项目目录中创建 templates 目录,用来放置我们的前端程序,在该目录中创建 index.html 作为客户端的入口

当前项目目录结构如下:

在这里插入图片描述

构建Web页面

  • index.html
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>铜锁SM2、SM3、SM4在线加密解密</title>
    <link rel="stylesheet" href="//unpkg.com/layui@2.6.8/dist/css/layui.css"/>
    <script src="//unpkg.com/layui@2.6.8/dist/layui.js"></script>
</head>
<body>
<div style="padding: 20px 20px">
    <div class="layui-tab">
        <ul class="layui-tab-title">
            <li class="layui-this">SM4加解密算法</li>
            <li>SM3杂凑算法</li>
            <li>SM2签名和验签</li>
        </ul>
        <div class="layui-tab-content">
            <div class="layui-tab-item layui-show">
                <div class="layui-row layui-anim-scale pt10" style="width: 100%;">
                    <div class="layui-col-md5">
                    <textarea style="resize: none;min-height: 280px;"
                              placeholder="在此输入明文,选择对应的加密方式,也可以加入密钥,然后加密即可。"
                              class="layui-textarea w99 fl m-h100" id="msg_source"></textarea>
                    </div>
                    <div class="layui-col-md2">
                        <form class="layui-form" action="" onsubmit="return !1;">
                            <div class="layui-form-item layui-col-md-offset2">
                                <div class="layui-input-inline fr w200 xpswd"><input type="text" name="text" id="pwd"
                                                                                     placeholder="在此输入密钥"
                                                                                     autocomplete="off"
                                                                                     class="layui-input">
                                </div>
                            </div>
                            <div class="layui-form-item layui-col-md-offset2">
                                <div class="layui-input-inline fr w200 mbt">
                                    <button class="layui-btn" onclick="decrypt();"><i class="layui-icon m-hide"></i>解密
                                    </button>
                                    <button class="layui-btn" onclick="encrypt();">加密<i
                                            class="layui-icon m-hide"></i>
                                    </button>
                                </div>
                            </div>
                        </form>
                    </div>
                    <div class="layui-col-md5"><textarea name="cipher" class="layui-textarea w99 fr "
                                                         placeholder="加密后的密文会显示在这里。也可以是待解密的密文。"
                                                         style="resize: none;min-height: 280px;" id="encrypt_result"
                                                         ondblclick="this.focus();this.select();"></textarea></div>
                </div>
            </div>
            <div class="layui-tab-item">
                <div>
                    <textarea style="resize: none;height: 200px;" placeholder="原文放到这里即可。"
                              class="layui-textarea w99 fl " id="source" maxlength="1000"></textarea>
                </div>
                <div style="display: inline-block;margin-top: 10px;margin-bottom:20px;">
                    <button class="layui-btn" id="ensm3" onclick="ensm3()">SM3加密<i class="layui-icon"></i></button>
                </div>
            </div>
            <div class="layui-tab-item">
                <div>
                    <button type="button" class="layui-btn" id="sign_file">
                        <i class="layui-icon">&#xe67c;</i>上传需要签名的文件
                    </button>

                    <div style="display: inline-block;margin-top: 10px;margin-bottom:20px;">
                        <button class="layui-btn" id="sign" onclick="download()">下载签名文件<i class="layui-icon"></i>
                        </button>
                    </div>
                </div>

                <div>
                    <button type="button" class="layui-btn" id="upload_origin_file">
                        <i class="layui-icon">&#xe67c;</i>上传源文件
                    </button>

                    <button type="button" class="layui-btn" id="upload_sign_file">
                        <i class="layui-icon">&#xe67c;</i>上传签名文件
                    </button>

                    <div style="display: inline-block;margin-top: 10px;margin-bottom:20px;">
                        <button class="layui-btn" onclick="verify()">验证签名<i class="layui-icon"></i></button>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

</body>
<script>
    function ajaxRequest(url, data, onSuccess, onError) {
        var xhr = new XMLHttpRequest();

        xhr.open('POST', url, true);

        xhr.onreadystatechange = function () {
            if (xhr.readyState === XMLHttpRequest.DONE) {
                if (xhr.status === 200) {
                    onSuccess(JSON.parse(xhr.responseText));
                } else {
                    onError(JSON.parse(xhr.statusText));
                }
            }
        };

        var formData = new FormData();

        for (var key in data) {
            formData.append(key, data[key]);
        }
        xhr.send(formData);
    }

    // 获取 id 为 msg_source 的元素
    var source = document.getElementById('msg_source');
    var source_text = document.getElementById('source');
    var pwd = document.getElementById('pwd');

    // 获取 id 为 encrypt_result 的元素
    var result = document.getElementById('encrypt_result');

    function encrypt() {
        console.log('加密')
        const v = source.value
        const pass = pwd.value
        if (!v || v === '') {
            return alert('加密数据为空')
        }
        if (!pass || pass === '') {
            return alert('密钥为空')
        }


        ajaxRequest('http://127.0.0.1:5000/sm4_cbc_encrypt', {'msg': v.trim(), 'key': pass.trim()}, function (res) {
            console.log(res);
            result.value = res.output;
        }, function (err) {
            console.log(err);
        })
    }

    function decrypt() {

        console.log('解密')
        const v = result.value.trim()
        if (!v || v === '') {
            return alert('解密数据为空')
        }

        const pass = pwd.value.trim()
        if (!pass || pass === '') {
            return alert('密钥为空')
        }

        ajaxRequest('http://127.0.0.1:5000/sm4_cbc_decrypt', {'msg': v, 'key': pass}, function (res) {
            console.log(res);
            if (res.error !== '') {
                return layer.alert('解密失败:' + res.error, {'icon': 2});
            }
            source.value = res.output;
        }, function (err) {
            console.log(err);
        })
    }

    function ensm3() {
        console.log('sm3加密')
        const v = source_text.value
        if (!v || v === '') {
            return alert('加密数据为空')
        }
        ajaxRequest('http://127.0.0.1:5000/sm3_dgst', {'msg': v.trim()}, function (res) {
            console.log(res);
            source_text.value = res.output;
        }, function (err) {
            console.log(err);
        })
    }

    var file_path = ''
    var origin_file_path = ''
    var sign_file_path = ''

    function download() {
        console.log('file_path')
        if (!file_path || file_path === '') {
            return alert('签名文件未上传')
        }

        var xhr = new XMLHttpRequest();
        xhr.open('POST', 'http://127.0.0.1:5000/download', true);
        xhr.responseType = 'blob';

        xhr.onload = function () {
            if (xhr.status === 200) {
                var blob = new Blob([xhr.response], {type: 'application/octet-stream'});
                var a = document.createElement('a');
                a.href = window.URL.createObjectURL(blob);
                a.download = Math.floor(Math.random() * 10000) + '_sign_file';
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                layer.alert('下载签名文件成功', {'icon': 1});
            } else {
                console.log(xhr.statusText);
            }
        };

        var fData = new FormData();
        fData.append('file_path', file_path);
        console.log(file_path);
        console.log(fData)
        xhr.send(fData);
    }

    function verify() {
        console.log('verify')
        const v = source.value
        if (!origin_file_path || origin_file_path === '') {
            return alert('原始文件未上传!')
        }
        if (!sign_file_path || sign_file_path === '') {
            return alert('签名文件未上传!')
        }

        ajaxRequest('http://127.0.0.1:5000/sm2_verify', {
            'file_path': origin_file_path,
            'sign_file_path': sign_file_path
        }, function (res) {
            console.log(res);
            layer.alert(res.output);
        }, function (err) {
            console.log(err);
        })
    }

    uploadFile('#sign_file', function (res) {
        ajaxRequest('http://127.0.0.1:5000/sm2_sign', {'path': res.path}, function (sign_res) {
            file_path = sign_res.path
        }, function (sign_err) {
            console.log(sign_err);
        })
    })

    uploadFile('#upload_origin_file', function (res) {
        origin_file_path = res.path
    })

    uploadFile('#upload_sign_file', function (res) {
        sign_file_path = res.path
    })

    function uploadFile(elem, doneCallback, errorCallback) {
        layui.use('upload', function () {
            var upload = layui.upload;
            //执行实例
            var uploadInst = upload.render({
                elem: elem,
                accept: 'file',
                url: 'http://127.0.0.1:5000/upload',
                done: function (res) {
                    doneCallback(res);
                },
                error: function () {
                    errorCallback();
                }
            });
        });
    }
</script>
</html>

项目预览

我们需要在容器中启动该项目:

python3 main.py

并输入 127.0.0.1:5000 在浏览器中进行预览,最终效果如下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

学习系统编程No.19【进程间通信之控制进程】

引言&#xff1a; 北京时间&#xff1a;2023/4/13/8:00&#xff0c;早八人&#xff0c;早八魂&#xff0c;时间不怎么充足&#xff0c;磨磨引言刚好&#xff0c;学习Linux和Linux有关的系统级知识已经许久了&#xff0c;在不知不觉之中&#xff0c;发现自己已经更到了第19篇&a…

3D视觉之深度相机方案

随着机器视觉&#xff0c;自动驾驶等颠覆性的技术逐步发展&#xff0c;采用 3D 相机进行物体识别&#xff0c;行为识别&#xff0c;场景 建模的相关应用越来越多&#xff0c;可以说 3D 相机就是终端和机器人的眼睛。 3D 相机 3D 相机又称之为深度相机&#xff0c;顾名思义&…

openDriver开源插件main.js源码分析

、基础要求 阅读本文章需要对以下知识有相关的了解 Threejs 3D渲染引擎dat.gui界面控制插件webgl三维绘图协议、着色器相关知识UV坐标、XYZ惯性坐标XODR文件格式 拓展 自动驾驶场景仿真标准&#xff08;一&#xff09;- OpenDRIVE - 知乎 《OpenDRIVE1.6规格文档》3_open…

2023年SICWGHS两大高含金量商赛组队招募中

想参加商赛&#xff0c;问了周围一圈朋友&#xff0c;不是没时间就是没兴趣&#xff0c;找个靠谱的队友怎么这么难&#xff1f; 相信这是不少商赛热爱者的共同烦恼&#xff0c;别急&#xff01;翰林来承包你的“找队友”任务&#xff0c;各路学霸等你来pick&#xff01; 两大…

屏幕亮度调节工具:Simple Screen Shade Mac

Simple Screen Shade Mac版是mac上一款优秀的屏幕颜色亮度调节工具&#xff0c;能够让我们Mac电脑的显示器背景变暗&#xff0c;这样可以保护你眼睛的健康并保持舒适。Simple Screen Shade 旨在实现最大程度的简单性和易用性。你可以设置灰色背景以减轻明亮鲜艳的色彩&#xff…

上海亚商投顾:沪指跌近2%险守3300点 AI概念股集体重挫

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 三大指数今日放量调整&#xff0c;深成指午后跌超2%&#xff0c;沪指、创业板指均跌近2%&#xff0c;科创50指数跌…

java-word模板转化为pdf

文章目录 一、引入包1.1在pom引入1.2 因为我们的项目是打包成jar,所以以上方法在本地idea运行没有问题&#xff0c;linux系统不行1.2.1解决方法11.2.2解决方法2 二、配置文件--License.xml--去除水印2.1 license.xml直接放到resources的根目录下即可2.2 工具类 三、调用效果 一…

部署架构 因为单体架构痛点 升级到微服务架构

如图为单体部署 痛点 多人协作可能产生很多的回归测试 代码管理复杂度提升 软件包升级会导致增加测试次数 举例 单体电商 1增加功能(增加小程序平台) 2 并发增加 出现 1 代码复用 2 系统间相互调用 3 接口不仅要对外服务&#xff0c;也得对内提供接口 4 数据分析功…

OTG是什么意思?

OTG是什么意思&#xff1f; OTG是怎么样实现的&#xff1f; TYPE-C接口的手机如何实现同时充电OTG功能&#xff1f; OTG是什么意思&#xff1f; OTG是On-The-Go的缩写&#xff0c;是一项新兴技术&#xff0c;主要应用于不同的设备或移动设备间的联接&#xff0c;进行数据交…

腾讯安全助力高校信息安全建设,护航湾区教育高质量发展

2023年4月20日-21日&#xff0c;首届大湾区信息网络安全大会在广州市长隆国际会展中心隆重召开。会议以“同筑安全屏障&#xff0c;共赢湾区未来”为主题&#xff0c;旨在响应国家安全战略&#xff0c;推动粤港澳大湾区信息网络安全的建设和发展&#xff0c;保障经济社会稳定运…

「OceanBase 4.1 体验」|国产分布式数据库不好用?别再打脸了

文章目录 分布式数据库分布式数据库有哪些&#xff1f;OceanBase4.1安装部署Index Skip Scan总结 随着互联网的高速发展和数据量的爆炸式增长&#xff0c;如何能够高效、可靠、安全地存储海量数据成为了每个企业的重要课题。 分布式数据库 分布式数据库通常是由多个独立的数据…

无人机各个类型介绍

为了执行&#xff0c;无人机可能由类似的元件制成&#xff0c;但无论是它们的能力&#xff0c;还是由什么组成的&#xff0c;它们都在某种程度上有所不同。大多数无人机都是为了执行特定任务而制造的&#xff0c;因此以特定的方式建造&#xff0c;以适应它们将要使用的环境。 …

docker-mysql-主从设计

一、docker主从 1.新建主从镜像 docker run -p 3307:3306 --name mysql -e MYSQL_ROOT_PASSWORDroot -d mysql:5.7.28 docker run -p 3308:3306 --name mysqlslave -e MYSQL_ROOT_PASSWORDroot -d mysql:5.7.282.分别进入两个容器&#xff0c;修改配置文件 #1.进入容器 $ do…

Java8新特性【函数式接口、Lambda表达、Stream流】

一、Lambda表达式 Java8是Java语言自JDK1.5以后的一个重大的里程碑版本&#xff0c;因为它增加了很多新特性&#xff0c;这些新特性会改变编程的风格和解决问题的方式。 例如&#xff1a;日期时间API、Lambda表达式&#xff08;λ&#xff09;、Stream API(操作集合)、方法引用…

用户量达6.33亿即时配送,拼的不止这些

上班忘了带电脑&#xff0c;回去取的话&#xff0c;来回要3个小时&#xff0c;还得损失半天薪资&#xff1b;好友生日&#xff0c;想在聚餐时给对方一个惊喜&#xff0c;但带着蛋糕去又容易提前剧透&#xff1b;老人突然生病在家&#xff0c;医院的号难挂、得排长队&#xff0c…

TSINGSEE视频能力在交通运输可视化管理平台项目中的应用

一、行业背景 为贯彻落实交通强国试点工作要求&#xff0c;提升交通建设工程信息化管理水平&#xff0c;进一步强化交通建设工程管理&#xff0c;各地政府部门决定在全省高速公路、国省道、大型水运、地方铁路、机场工程安装视频监控系统&#xff0c;在建交通建设项目尚未安装…

OldWang带你了解MySQL(九)

文章目录 &#x1f525;MySQL中的索引&#x1f525;MySQL中的索引类型&#x1f525;普通索引&#x1f525;唯一索引&#x1f525;主键索引&#x1f525;组合索引 &#x1f525;MySQL中的索引 索引介绍 索引是对数据库表中的一列或多列值进行排序的一种结构&#xff0c;使用索引…

【C++学习笔记】字符串、向量和数组

字符串类型 1.C语言风格字符串&#xff1a;char 变量名[] "字符串值" 1. char: 字符常量或者单个字符 单引号定义 &#xff1b;字符串常量用 双引号 定义 2. 输出直接用cout char str1[] "hello world"; cout << str1 << endl;2.C语言风格…

Linux环境下 通过V4L2读取视频+UDP发送图片文件

该图为整个项目的流程图 其中左边的流程为总流程&#xff0c;包括通过中断读取摄像头的帧数据&#xff0c;通过内存映射将内核态的数据映射到用户态&#xff0c;读取用户态的数据&#xff0c;采用循环发送图片数据。 右边是发送图片的流程图&#xff0c;将用户态的缓冲区的数…

780E编译底包教程

这里写目录标题 准备1 安装开发环境准备2 拉取编译工程源码 代码编译修改或者增加用户程序说明 准备 1 安装开发环境准备 需要用户自行安装好Xmake\vscode\git 环境教程传送门 2 拉取编译工程源码 注意, 需要两个库 主库 https://gitee.com/openLuat/LuatOS bsp库 https://…