算法基础--MD5算法介绍

news2024/11/24 4:20:51

1、简介

  MD5再开发过程中经常碰到的一种算法,因此感觉有必要对其原理进行更深入的了解一下。

2、算法概念

  散列函数,也称作哈希函数,消息摘要函数,单向函数或者杂凑函数。散列函数主要用于验证数据的完整性。通过散列函数,可以创建消息的“数字指纹”,消息接收方可以通过校验消息的哈希值来验证消息的完整性,防止消息被篡改。散列函数具有以下特性:

  • 散列函数的运算过程是不可逆的,这个称为散列函数的单向性。
  • 对于一个已知的消息及其散列值,要找到另外一个消息使其获得相同的散列值是不可能的,这个特性称为散列函数的弱碰撞性。这个特性可以用来防止消息伪造。
  • 任意两个不同消息的散列值一定不同。
  • 对原始消息长度没有限制。
      任何消息经过散列函数处理后,都会产生一个唯一的散列值,这个散列值可以用来验证消息的完整性。计算消息散列值的过程被称为“消息摘要”,计算消息散列值的算法被称为消息摘要算法。MD5算法是Hash算法的一种,叫做消息摘要算法。所谓摘要,从字面意思理解,是指内容的大概。在MD5算法中,这个摘要是指将任意数据映射成一个128位长的摘要信息。并且其是不可逆的,即从摘要信息无法反向推演中原文,在演算过程中,原文的内容也是有丢失的。因为MD5算法最终生成的是一个128位长的数据,从原理上说,有2^128种可能,这是一个非常巨大的数据,约等于3.4乘10的38次方,虽然这个是个天文数字,但是世界上可以进行加密的数据原则上说是无限的,因此是可能存在不同的内容经过MD5加密后得到同样的摘要信息,但这个碰中的概率非常小。
    在这里插入图片描述

3、应用场景

  MD5常用在密码加密中,一般为了保证用户密码的安全,在数据库中存储的都是用户的密码经过MD5加密后的值,在客户端用户输入密码后,也会使用MD5进行加密,这样即使用户的网络被窃听,窃听者依然无法拿到用户的原始密码,并且即使用户数据库被盗,没有存储明文的密码对用户来说也多了一层安全保障。MD5签名技术还常用于防止信息的篡改。使用MD5可以对信息进行签名,接收者拿到信息后只要重新计算签名和原始签名进行对比,即可知道数据信息是否中途被篡改了。

4、算法原理

  假设原始消息长度是b(以bit为单位),注意这里b可以是任意长度,并不一定要是8的整数倍。计算该消息MD5值的过程如下:

 信息填充

   在计算消息的MD5值之前,首先对原始信息进行填充,这里的信息填充分为两步。

  • 填充原始信息:对原始信息进行填充,填充之后,要求信息的长度对512取余等于448。填充的规则如下:假设原始信息长度为b bit,那么在信息的b+1 bit位填充1,剩余的位填充0,直到信息长度对512取余为448。这里有一点需要注意,如果原始信息长度对512取余正好等于448,这种情况仍然要进行填充,很明显,在这时我们要填充的信息长度是512位,直到信息长度对512取余再次等于448。所以,填充的位数最少为1,最大为512。
  • 填充信息长度:填充信息长度,我们需要把原始信息长度转换成以bit为单位,然后在第一步操作的结果后面填充64bit的数据表示原始信息长度。第一步对原始信息进行填充之后,信息长度对512取余结果为448,这里再填充64bit的长度信息,整个信息恰好可以被512整除。其实从后续过程可以看到,计算MD5时,是将信息分为若干个分组进行处理的,每个信息分组的长度是512bit。

 信息处理

  • 信息分组定义
    原始信息经过填充之后,最终得到的信息长度(bit)是512的整数倍,我们先对信息进行分组,每512bit为一个分组,然后再将每个信息分组(512bit)再细分为16个小的分组,每个小分组的长度为32bit。规定如下
  • Mp 代表经过填充之后的信息
  • LM 表示Mp的长度(以bit为单位)
  • N 表示分组个数,N = LM/512
  • M[i] 表示将原始信息进行分组后的第i个信息分组,其中i=1…N
  • X[i] 表示将M[i]进行分组后的第i个小分组,其中i=1…16

 标准幻数定义

 现定义四个标准幻数如下,

  • A = 01 23 45 67
  • B = 89 ab cd ef
  • C = fe dc ba 98
  • D = 76 54 32 10
    在计算机中存储时,采用小端存储方式,以A为例,A在Java中初始化的代码为为A=0x67452301

 常量表T

 T是一个常量表,T[i] = 4294967296 * abs(sin(i))的运算结果取整,其中i=1…64

 辅助方法

 T我们定义四个辅助方法。

  • F(x,y,z) = (x & y) | ((~x) & z)
  • G(x,y,z) = (x & z) | (y & (~z))
  • H(x,y,z) = x ^ y ^ z
  • I(x,y,z) = y ^ (x | (~z))
    其中,x,y,z长度为32bit

5、算法实现

#ifndef SRC_UTIL_MD5_H_
#define SRC_UTIL_MD5_H_

#include <string>
#include <iostream>
#include <cstdint>

namespace toolkit {

class MD5
{
public:
    typedef unsigned int size_type; // must be 32bit

    MD5();
    MD5(const std::string& text);
    void update(const unsigned char *buf, size_type length);
    void update(const char *buf, size_type length);
    MD5& finalize();
    std::string hexdigest() const;
    std::string rawdigest() const;
    friend std::ostream& operator<<(std::ostream&, MD5 md5);
private:
    void init();
    typedef uint8_t uint1; //  8bit
    typedef uint32_t uint4;  // 32bit
    enum {blocksize = 64}; // VC6 won't eat a const static int here

    void transform(const uint1 block[blocksize]);
    static void decode(uint4 output[], const uint1 input[], size_type len);
    static void encode(uint1 output[], const uint4 input[], size_type len);

    bool finalized;
    uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk
    uint4 count[2];   // 64bit counter for number of bits (lo, hi)
    uint4 state[4];   // digest so far
    uint1 digest[16]; // the result

    // low level logic operations
    static inline uint4 F(uint4 x, uint4 y, uint4 z);
    static inline uint4 G(uint4 x, uint4 y, uint4 z);
    static inline uint4 H(uint4 x, uint4 y, uint4 z);
    static inline uint4 I(uint4 x, uint4 y, uint4 z);
    static inline uint4 rotate_left(uint4 x, int n);
    static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
    static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
    static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
    static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
};


} /* namespace toolkit */

#endif /* SRC_UTIL_MD5_H_ */
/* interface header */
#include "MD5.h"
/* system implementation headers */
#include <cstdio>
#include <cstring>

namespace toolkit {

// Constants for MD5Transform routine.
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21

///

// F, G, H and I are basic MD5 functions.
inline MD5::uint4 MD5::F(uint4 x, uint4 y, uint4 z) {
    return (x&y) | (~x&z);
}

inline MD5::uint4 MD5::G(uint4 x, uint4 y, uint4 z) {
    return (x&z) | (y&~z);
}

inline MD5::uint4 MD5::H(uint4 x, uint4 y, uint4 z) {
    return x^y^z;
}

inline MD5::uint4 MD5::I(uint4 x, uint4 y, uint4 z) {
    return y ^ (x | ~z);
}

// rotate_left rotates x left n bits.
inline MD5::uint4 MD5::rotate_left(uint4 x, int n) {
    return (x << n) | (x >> (32-n));
}

// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
// Rotation is separate from addition to prevent recomputation.
inline void MD5::FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
    a = rotate_left(a+ F(b,c,d) + x + ac, s) + b;
}

inline void MD5::GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
    a = rotate_left(a + G(b,c,d) + x + ac, s) + b;
}

inline void MD5::HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
    a = rotate_left(a + H(b,c,d) + x + ac, s) + b;
}

inline void MD5::II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
    a = rotate_left(a + I(b,c,d) + x + ac, s) + b;
}

//

// default ctor, just initailize
MD5::MD5()
{
    init();
}

//

// nifty shortcut ctor, compute MD5 for string and finalize it right away
MD5::MD5(const std::string &text)
{
    init();
    update(text.c_str(), text.length());
    finalize();
}

//

void MD5::init()
{
    finalized=false;

    count[0] = 0;
    count[1] = 0;

    // load magic initialization constants.
    state[0] = 0x67452301;
    state[1] = 0xefcdab89;
    state[2] = 0x98badcfe;
    state[3] = 0x10325476;
}

//

// decodes input (unsigned char) into output (uint4). Assumes len is a multiple of 4.
void MD5::decode(uint4 output[], const uint1 input[], size_type len)
{
    for (unsigned int i = 0, j = 0; j < len; i++, j += 4)
        output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) |
        (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24);
}

//

// encodes input (uint4) into output (unsigned char). Assumes len is
// a multiple of 4.
void MD5::encode(uint1 output[], const uint4 input[], size_type len)
{
    for (size_type i = 0, j = 0; j < len; i++, j += 4) {
        output[j] = input[i] & 0xff;
        output[j+1] = (input[i] >> 8) & 0xff;
        output[j+2] = (input[i] >> 16) & 0xff;
        output[j+3] = (input[i] >> 24) & 0xff;
    }
}

//

// apply MD5 algo on a block
void MD5::transform(const uint1 block[blocksize])
{
    uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
    decode (x, block, blocksize);

    /* Round 1 */
    FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
    FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
    FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
    FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
    FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
    FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
    FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
    FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
    FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
    FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
    FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
    FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
    FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
    FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
    FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
    FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */

    /* Round 2 */
    GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
    GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
    GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
    GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
    GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
    GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
    GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
    GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
    GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
    GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
    GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
    GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
    GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
    GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
    GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
    GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */

    /* Round 3 */
    HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
    HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
    HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
    HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
    HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
    HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
    HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
    HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
    HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
    HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
    HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
    HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
    HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
    HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
    HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
    HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */

    /* Round 4 */
    II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
    II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
    II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
    II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
    II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
    II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
    II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
    II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
    II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
    II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
    II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
    II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
    II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
    II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
    II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
    II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */

    state[0] += a;
    state[1] += b;
    state[2] += c;
    state[3] += d;

    // Zeroize sensitive information.
    memset(x, 0, sizeof x);
}

//

// MD5 block update operation. Continues an MD5 message-digest
// operation, processing another message block
void MD5::update(const unsigned char input[], size_type length)
{
    // compute number of bytes mod 64
    size_type index = count[0] / 8 % blocksize;

    // Update number of bits
    if ((count[0] += (length << 3)) < (length << 3))
        count[1]++;
    count[1] += (length >> 29);

    // number of bytes we need to fill in buffer
    size_type firstpart = 64 - index;

    size_type i;

    // transform as many times as possible.
    if (length >= firstpart)
    {
        // fill buffer first, transform
        memcpy(&buffer[index], input, firstpart);
        transform(buffer);

        // transform chunks of blocksize (64 bytes)
        for (i = firstpart; i + blocksize <= length; i += blocksize)
            transform(&input[i]);

        index = 0;
    }
    else
        i = 0;

    // buffer remaining input
    memcpy(&buffer[index], &input[i], length-i);
}

//

// for convenience provide a verson with signed char
void MD5::update(const char input[], size_type length)
{
    update((const unsigned char*)input, length);
}

//

// MD5 finalization. Ends an MD5 message-digest operation, writing the
// the message digest and zeroizing the context.
MD5& MD5::finalize()
{
    static unsigned char padding[64] = {
        0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    };

    if (!finalized) {
        // Save number of bits
        unsigned char bits[8];
        encode(bits, count, 8);

        // pad out to 56 mod 64.
        size_type index = count[0] / 8 % 64;
        size_type padLen = (index < 56) ? (56 - index) : (120 - index);
        update(padding, padLen);

        // Append length (before padding)
        update(bits, 8);

        // Store state in digest
        encode(digest, state, 16);

        // Zeroize sensitive information.
        memset(buffer, 0, sizeof buffer);
        memset(count, 0, sizeof count);

        finalized=true;
    }

    return *this;
}

//

// return hex representation of digest as string
std::string MD5::hexdigest() const
{
    if (!finalized)
        return "";

    char buf[33];
    for (int i=0; i<16; i++)
        sprintf(buf+i*2, "%02x", digest[i]);
    buf[32]=0;

    return std::string(buf);
}

std::string MD5::rawdigest() const{
    return std::string((char *)digest, sizeof(digest));
}


//

std::ostream& operator<<(std::ostream& out, MD5 md5)
{
    return out << md5.hexdigest();
}

//

std::string md5(const std::string str)
{
    MD5 md5 = MD5(str);

    return md5.hexdigest();
}
} /* namespace toolkit */

参考资料
MD5加密原理解析及OC版原理实现:https://developer.aliyun.com/article/790494
MD5算法原理及实现:https://www.jianshu.com/p/93a8ab5bfeb9
一文读懂 MD5 算法:https://segmentfault.com/a/1190000021691476

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

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

相关文章

自然语言处理从入门到应用——自然语言处理的应用任务

分类目录&#xff1a;《自然语言处理从入门到应用》总目录 本文介绍信息抽取、情感分析、问答系统、机器翻译和对话系统等自然语言处理应用任务。这些任务可以直接或间接地以产品的形式为终端用户提供服务&#xff0c;是自然语言处理研究应用落地的主要技术。 信息抽取 信息抽…

天气预报信息获取程序--GUI--可以使用

上次正对项目中需要填写项目日志&#xff0c;制作了一个命令行版本的下载天气信息的程序&#xff0c;满足日常需要&#xff0c;调整一下界面版本的程序 如果大家使用命令行的可以使用下面的版本&#xff08;连接&#xff09; https://ht666666.blog.csdn.net/article/details…

逻辑漏洞学习-知识点总结

逻辑漏洞就是程序在实现业务逻辑上存在的错误&#xff0c;辑漏洞的出现通常是因为程序在设计业务逻辑时考虑不够全面&#xff0c;或者程序员的思维过程存在瑕疵&#xff0c;没有充分考虑到各种可能的情况 大部分程序员在设计的时候&#xff0c;目标是实现功能需求&#xff0c;…

Linux基础知识点 有这篇就足够了!!

❄️作者介绍&#xff1a;奇妙的大歪❄️ &#x1f380;个人名言&#xff1a;但行前路&#xff0c;不负韶华&#xff01;&#x1f380; &#x1f43d;个人简介&#xff1a;云计算网络运维专业人员&#x1f43d; 目录 一、 从认识操作系统开始 1.1 操作系统简介 1.2 操作系统…

chatgpt赋能Python-python分表

介绍 Python是一种流行的编程语言&#xff0c;适用于各种应用程序开发&#xff0c;包括网络应用程序、数据库应用程序以及数据分析和科学计算。Python分表是基于Python编写的分表工具&#xff0c;可以帮助开发人员更轻松地管理大型数据库表格。 Python分表是如何工作的&#…

0219-810

3GPP TS 02.19 V8.1.0 (2005-06) 前言 本技术规范由第三代合作伙伴计划 (3GPP) 制定。 本文件的内容取决于 TSG 的持续工作&#xff0c;并可能在 TSG 正式批准后发生变化。 如果 TSG 修改本文档的内容&#xff0c;TSG 将重新发布 确定发布日期的变化和版本号的增加如下&…

低代码开发平台选择指南:如何选出最适合企业的低代码平台?

低代码平台的兴起改变了公司处理软件开发的方式。这些平台使组织能够快速高效地构建应用程序&#xff0c;该应用程序可以利用预设组件和开箱功能。但是&#xff0c;因为有这么多低代码平台可以使用&#xff0c;所以为你的组织选择合适的平台可能是一个挑战。本文将探索如何低代…

FreeRTOS任务切换

PendSV异常 SVC 用于产生系统函数的调用请求。例如&#xff0c;操作系统不让用户程序直接访问硬件&#xff0c;而是通过提供一些系统服务函数&#xff0c;用户程序使用 SVC 发出对系统服务函数的呼叫请求&#xff0c;以这种方法调用它们来间接访问硬件。因此&#xff0c;当用户…

(字符串 ) 459. 重复的子字符串——【Leetcode每日一题】

❓459. 重复的子字符串 难度&#xff1a;简单 给定一个非空的字符串 s &#xff0c;检查是否可以通过由它的一个子串重复多次构成。 示例 1: 输入: s “abab” 输出: true 解释: 可由子串 “ab” 重复两次构成。 示例 2: 输入: s “aba” 输出: false 示例 3: 输入: s “…

IDEA+Mysql调试常见异常解决办法_kaic

IDEA导入项目出现Error: java: 程序包javax.servlet.http不存在错误的解决办法 解决方法&#xff1a;打开File>Project Structure>Libraries&#xff0c;点击右侧加号&#xff0c;寻找到tomcat的lib文件夹&#xff0c;点击ok&#xff0c;IDEA会自动重新Rebuild Project&…

数据结构 | 图的深度优先遍历和广度优先遍历(C语言)

一、数据结构定义 1、图 #define MaxVertexNum 100 // 最大可存储的节点数目/*图*/ typedef char VexterType; typedef int EdgeType;typedef struct GraphMatrix {VexterType Vexs[MaxVertexNum]; //结点 EdgeType Edges[MaxVertexNum][MaxVertexNum]; //边int vexnum, a…

使用 MCSM 面板一键搭建我的世界服务器,并内网穿透公网远程联机

文章目录 前言1.Mcsmanager安装2.创建Minecraft服务器3.本地测试联机4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射内网端口 5.远程联机测试6. 配置固定远程联机端口地址6.1 保留一个固定TCP地址6.2 配置固定TCP地址 7. 使用固定公网地址远程联机 转载自远程穿透文章&…

【AI】Stable-Diffusion-WebUI使用指南

注&#xff1a;csdn对图片有审核&#xff0c;审核还很奇葩&#xff0c;线稿都能违规&#xff0c;为保证完整的阅读体验建议移步至个人博客阅读 最近AI绘画实现了真人照片级绘画水准&#xff0c;导致AI绘画大火&#xff0c;公司也让我研究研究&#xff0c;借此机会正好了解一下…

图像处理:GrapeCity Documents Imaging 6.1.2 Crack

适用于 .NET 6 的快速、强大的映像 API 库,在代码中应用高级图像处理&#xff0c;零依赖关系。 加载和保存图像文件&#xff0c;如BMP&#xff0c;JPEG&#xff0c;TIFF&#xff0c;GIF&#xff0c;ICO&#xff0c;SVG&#xff0c;WebP和PNG 对灰度和 RGB 图像应用抖动和阈值等…

Ribbon 负载均衡策略 —— 图解、源码级解析

文章目录 负载均衡策略RandomRuleRoundRobinRuleRetryRuleWeightedResponseTimeRuleBestAvailableRuleAvailabilityFilteringRuleZoneAvoidanceRule Ribbon 负载均衡策略源码RandomRule源码RoundRobinRule源码BestAvailableRule源码RetryRule源码 通过本文你可以学习到&#xf…

自学大语言模型之BERT

BERT 模型由 Jacob Devlin、Ming-Wei Chang、Kenton Lee 和 Kristina Toutanova在BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding中提出。它是一种双向变换器&#xff0c;使用掩码语言建模目标和对包含多伦多图书语料库和维基百科的大型语…

开源高星精选,10个2023企业级Python测试项目,再不学习时间就没了

纸上得来终觉浅&#xff0c;光学习理论知识是不够的。 想要学好软件测试必须要结合实战项目深入掌握&#xff0c;今天给大家分享十个2022最新企业级Python软件测试项目&#xff1a; ​ 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; ▌Rank 1&#xf…

SEW-Movifit软件的调试步骤

首先安装软件&#xff08;名称和版本为SEW_Software_MotionStudio_V5-9-0-4-compact&#xff09;。安装完毕后打开软件&#xff0c;新建一个工程。 3、新建完成之后会进入如下画面。 4、点击红框内的图标进行设置 5、打开后会显示如下画面&#xff0c;在下拉菜单中选择serial这…

【Unity3D】高斯模糊特效

1 高斯模糊原理 边缘检测特效中使用了卷积运算进行了边缘检测&#xff0c;本文实现的高斯模糊特效同样使用了卷积运算&#xff0c;关于卷积核和卷积运算的概念&#xff0c;读者可以参考边缘检测特效。 本文完整资源见→Unity3D高斯模糊特效。 我们将用于模糊处理的卷积核称为模…

C++模拟牛顿力学(2D)

简介 如何用计算机来模拟真实世界呢&#xff1f;计算机最大的功能是计算&#xff0c;而物理学的种种公式就把现实世界中的物理规律以数学的语言描绘了出来&#xff0c;从而使我们可以通过计算大致模拟现实世界的物体运动。因此不难想到把物理学定律&#xff08;这里用的是牛顿…