Jump to content

墨香年少

Administrators
  • Content Count

    300
  • Joined

  • Last visited

  • Days Won

    18

Everything posted by 墨香年少

  1. SDL2 - 一个跨平台开发库,旨在提供硬件抽象层。 FLTK - 适用于 UNIX®/Linux® (X11)、Microsoft® Windows® 和 MacOS® X 的跨平台 C++ GUI 工具包。 asio - 用于网络和低级 I/O 编程的跨平台 C++ 库。 g3log - 一个易于使用的异步、“崩溃安全”记录器。 lua - 一种强大、高效、轻量级、可嵌入的脚本语言。 sol2 - 快速、简单的 C++ 和 Lua 绑定。 tinyxml2 - 一个简单、小型、高效的 C++ XML 解析器。 utf8-cpp - 一个简单、可移植且轻量级的 C++ 库,用于 UTF-8 字符串处理。 libpng - 官方 PNG 参考库,修补了 APNG 支持。 ThreadPool - 一个简单的 C++11 线程池实现。 SQLiteCpp - SQLiteC++ (SQLiteCpp) 是一个智能且易于使用的 C++ SQLite3 包装器。
  2. 有很多非中国的程序员在线接单网站,其中一些包括: Upwork: 这是全球最大的自由职业者平台之一,覆盖了各种技能领域,包括软件开发和编程。 Freelancer: 类似于Upwork,Freelancer也是一个全球自由职业者市场,提供软件开发和编程项目。 Toptal: Toptal聚焦于连接顶尖的自由职业者与客户,提供高质量的软件开发和设计服务。 Guru: Guru是一个在线自由职业者市场,提供软件开发、网站开发等服务。 PeoplePerHour: 这是一个英国为基础的在线自由职业者市场,提供软件开发、设计等服务。 Fiverr: Fiverr上有各种技能的自由职业者,包括软件开发、网站设计等,客户可以根据需求选择合适的服务。 这些平台提供了连接客户和自由职业者的渠道,并提供支付、沟通和项目管理工具,以确保项目顺利完成。
  3. 通过/proc文件系统:Linux的/proc文件系统包含了系统运行时的各种信息,包括当前运行的进程信息。你可以遍历/proc目录下的每个子目录(以数字命名的目录,每个目录名对应一个进程ID),并读取其中的status文件来获取进程名称等信息。 使用popen和grep:通过执行ps -A命令并结合grep来搜索特定的进程名。如果命令的输出非空,则表示进程存在。这种方法适用于简单的场景,但可能不是最高效或最可靠的方式。 使用系统调用kill:通过发送信号0(不会结束进程)给指定的进程ID(如果你已知),如果调用成功,则表明进程存在。注意,这需要适当的权限。 检测进程使用的端口 读取/proc/net/tcp和/proc/net/udp文件:这些文件包含了当前系统TCP和UDP端口的使用情况。通过解析这些文件,可以找出特定进程正在监听或使用的端口。 使用lsof命令:lsof是一个列出打开文件的工具,对于网络连接,打开的“文件”是网络套接字。你可以通过popen执行lsof -i命令并解析输出来查找特定进程的端口使用情况。 示例代码 以下是一个使用C语言通过读取/proc文件系统来检测特定进程是否存在的简单示例。注意,这只是一个基本的例子,可能需要根据具体需求进行调整: #include <stdio.h> #include <dirent.h> #include <string.h> int process_exists(const char* process_name) { DIR *dir; struct dirent *ent; char buf[512]; // 打开/proc目录 if ((dir = opendir("/proc")) != NULL) { // 遍历/proc下的所有项 while ((ent = readdir(dir)) != NULL) { long pid; char cmdline[256]; FILE *fp; // 尝试将目录名转换为pid if ((pid = strtol(ent->d_name, NULL, 10)) > 0) { // 构建cmdline文件的路径 snprintf(cmdline, sizeof(cmdline), "/proc/%ld/cmdline", pid); // 尝试打开文件 if ((fp = fopen(cmdline, "r")) != NULL) { // 读取命令行内容 if (fgets(buf, sizeof(buf), fp) != NULL) { // 检查进程名称是否匹配 if (strstr(buf, process_name) != NULL) { fclose(fp); closedir(dir); return 1; // 找到进程 } } fclose(fp); } } } closedir(dir); } return 0; // 未找到进程 } int main() { const char* process_name = "your_process_name_here"; if (process_exists(process_name)) { printf("Process '%s' exists.\n", process_name); } else { printf("Process '%s' does not exist.\n", process_name); } return 0; }
  4. systemctl list-units --type=service --state=running | grep messenger 这条命令的作用是: systemctl list-units --type=service --state=running:列出所有类型为服务且当前状态为运行中的单元。 | grep messenger:通过管道将前一个命令的输出传递给grep命令,grep将过滤出包含“messenger”的行。 如果有任何正在运行的服务的名称中包含“messenger”,这条命令会列出它们。如果没有输出,那么可能没有符合条件的正在运行的服务。 请注意,这个命令区分大小写。如果你想要进行不区分大小写的搜索,可以使用grep的-i选项: systemctl list-units --type=service --state=running | grep -i messenger
  5. // src/Service/PaymentLogService.php namespace App\Service; class PaymentLogService { private $logDirectory; public function __construct(string $logDirectory) { $this->logDirectory = $logDirectory; } public function appendToPaymentLog($pno, $content): void { $filePath = $this->logDirectory . '/' . $pno; // 确保目录存在 if (!file_exists(dirname($filePath))) { mkdir(dirname($filePath), 0777, true); } // 追加内容到文件,如果文件不存在则创建 file_put_contents($filePath, $content, FILE_APPEND); } } # config/services.yaml services: App\Service\PaymentLogService: arguments: $logDirectory: '%kernel.project_dir%/log' // src/Controller/SomeController.php namespace App\Controller; use Symfony\Component\HttpFoundation\Response; use App\Service\PaymentLogService; class SomeController { private $paymentLogService; public function __construct(PaymentLogService $paymentLogService) { $this->paymentLogService = $paymentLogService; } public function appendLogAction($pno): Response { $content = date('Y-m-d H:i:s') . "\n"; $this->paymentLogService->appendToPaymentLog($pno, $content); return new Response('Log updated.'); } }
  6. #include <windows.h> #include <stdio.h> // 打开串口 HANDLE open_serial_port(LPCSTR port_name, DWORD baud_rate) { HANDLE hSerial; DCB dcbSerialParams = {0}; COMMTIMEOUTS timeouts = {0}; // 打开串口 hSerial = CreateFile(port_name, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hSerial == INVALID_HANDLE_VALUE) { fprintf(stderr, "Error opening serial port\n"); return INVALID_HANDLE_VALUE; } // 获取当前串口配置 dcbSerialParams.DCBlength = sizeof(dcbSerialParams); if (!GetCommState(hSerial, &dcbSerialParams)) { fprintf(stderr, "Error getting serial port state\n"); CloseHandle(hSerial); return INVALID_HANDLE_VALUE; } // 配置串口 dcbSerialParams.BaudRate = baud_rate; dcbSerialParams.ByteSize = 8; // 数据位为8位 dcbSerialParams.StopBits = ONESTOPBIT; // 停止位为1 dcbSerialParams.Parity = NOPARITY; // 无奇偶校验位 if (!SetCommState(hSerial, &dcbSerialParams)) { fprintf(stderr, "Error setting serial port state\n"); CloseHandle(hSerial); return INVALID_HANDLE_VALUE; } // 设置超时 timeouts.ReadIntervalTimeout = 50; timeouts.ReadTotalTimeoutConstant = 50; timeouts.ReadTotalTimeoutMultiplier = 10; timeouts.WriteTotalTimeoutConstant = 50; timeouts.WriteTotalTimeoutMultiplier = 10; if (!SetCommTimeouts(hSerial, &timeouts)) { fprintf(stderr, "Error setting timeouts\n"); CloseHandle(hSerial); return INVALID_HANDLE_VALUE; } return hSerial; } // 写数据到串口 BOOL write_serial_port(HANDLE hSerial, LPCVOID data, DWORD size) { DWORD bytes_written; return WriteFile(hSerial, data, size, &bytes_written, NULL); } // 从串口读数据 BOOL read_serial_port(HANDLE hSerial, LPVOID buffer, DWORD size, DWORD *bytes_read) { return ReadFile(hSerial, buffer, size, bytes_read, NULL); } // 关闭串口 void close_serial_port(HANDLE hSerial) { CloseHandle(hSerial); } // 示例使用 int main() { HANDLE hSerial = open_serial_port("COM3", CBR_9600); // 以9600波特率打开COM3 if (hSerial == INVALID_HANDLE_VALUE) return 1; char data_to_send[] = "Hello, serial port!"; if (!write_serial_port(hSerial, data_to_send, sizeof(data_to_send))) { fprintf(stderr, "Error writing to serial port\n"); } char read_buf[128]; DWORD bytes_read; if (read_serial_port(hSerial, read_buf, sizeof(read_buf), &bytes_read)) { printf("Received: %.*s\n", (int)bytes_read, read_buf); } else { fprintf(stderr, "Error reading from serial port\n"); } close_serial_port(hSerial); return 0; } 这段代码中,open_serial_port函数用于打开指定的串口并进行配置,write_serial_port和read_serial_port函数分别用于向串口写数据和从串口读数据,最后通过close_serial_port函数关闭串口。注意,这段代码只是一个基础的示例,实际使用中可能需要根据具体需求进行调整,例如处理错误情况、调整超时设置等。在编译运行这段代码时,需要确保你的开发环境支持Windows API调用,并且链接了kernel32.lib库(如果使用Microsoft Visual C++,通常这是默认配置)。
  7. #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <termios.h> #include <string.h> // 函数声明 int open_serial(const char *device); int setup_serial(int fd, int speed, int parity); int serial_read(int fd, char *buf, int size); int serial_write(int fd, const char *buf, int size); void close_serial(int fd); // 打开串口设备 int open_serial(const char *device) { int fd = open(device, O_RDWR | O_NOCTTY | O_SYNC); if (fd < 0) { perror("open_serial() failed"); return -1; } return fd; } // 配置串口参数 int setup_serial(int fd, int speed, int parity) { struct termios tty; memset(&tty, 0, sizeof tty); if (tcgetattr(fd, &tty) != 0) { perror("setup_serial() failed"); return -1; } cfsetospeed(&tty, speed); cfsetispeed(&tty, speed); tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars tty.c_iflag &= ~IGNBRK; // disable break processing tty.c_lflag = 0; // no signaling chars, no echo, // no canonical processing tty.c_oflag = 0; // no remapping, no delays tty.c_cc[VMIN] = 0; // read doesn't block tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls, // enable reading tty.c_cflag &= ~(PARENB | PARODD); // shut off parity tty.c_cflag |= parity; tty.c_cflag &= ~CSTOPB; tty.c_cflag &= ~CRTSCTS; if (tcsetattr(fd, TCSANOW, &tty) != 0) { perror("setup_serial() failed"); return -1; } return 0; } // 读取串口数据 int serial_read(int fd, char *buf, int size) { int n = read(fd, buf, size); if (n < 0) { perror("serial_read() failed"); return -1; } return n; } // 向串口写入数据 int serial_write(int fd, const char *buf, int size) { int n = write(fd, buf, size); if (n < 0) { perror("serial_write() failed"); return -1; } return n; } // 关闭串口设备 void close_serial(int fd) { close(fd); } // 主函数示例 int main() { int fd = open_serial("/dev/ttyUSB0"); // 替换为实际的串口设备文件 if (fd < 0) return 1; if (setup_serial(fd, B9600, 0) < 0) { // 设置波特率为 9600 close_serial(fd); return 1; } const char *msg = "Hello, serial port!"; serial_write(fd, msg, strlen(msg)); // 发送数据 char buf[100]; int n = serial_read(fd, buf, sizeof(buf) - 1); // 读取数据 if (n >= 0) { buf[n] = '\0'; printf("Received: %s\n", buf); } close_serial(fd); return 0; }
  8. 运行下面的命令: echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/openssl-3.2.0.conf echo "/usr/local/lib64" | sudo tee -a /etc/ld.so.conf.d/openssl-3.2.0.conf 然后执行: sudo ldconfig
  9. 墨香年少

    OPcache JIT

    在 PHP 8.0 及更高版本中,opcache.jit 配置选项用于控制 JIT(Just-In-Time compilation)编译器的行为。opcache.jit 的值定义了 JIT 编译的触发模式和性能特性,其中 1205 是一个特定的配置值,代表了 JIT 编译器的配置和优化级别。 opcache.jit=1205 这个值实际上是一个四位数字,每一位数字代表了不同的配置意义: 第一位(1):定义了 JIT 编译的触发方式。在这个例子中,1 代表使用“触发”模式,即 JIT 编译会在 PHP 代码执行时根据特定的触发条件自动启动。 第二位(2):指定了 JIT 编译的操作模式。2 通常表示“函数”模式(Function JIT),它将在函数级别进行 JIT 编译,而不是在更细粒度的热点代码块级别。这意味着每个函数都会被尝试编译为机器代码。 第三位(0)和第四位(5):这两位一起决定了 JIT 编译器的优化级别。05 是一个相对较高的优化级别,它会尝试进行较多的优化以提高代码执行的速度。 在 PHP 的 JIT 配置中,这个“触发”模式和优化级别的组合被设计来平衡编译时间和执行性能。较高的优化级别可能会增加编译时间,但通常会提供更快的执行速度。 不过,需要注意的是,JIT 的性能提升效果极大地依赖于应用的特定工作负载。在某些应用中,启用 JIT 可以显著提高性能,特别是在计算密集型的场景下。然而,在其他场景,如 I/O 密集型的 Web 应用中,性能提升可能不那么明显。因此,选择合适的 JIT 配置并进行适当的性能测试对于充分利用 JIT 带来的潜在优势是非常重要的。
  10. 墨香年少

    OPcache JIT

    OPcache JIT(Just-In-Time compilation,即时编译)是 PHP 8.0 及更高版本中引入的一项新功能,旨在进一步提高 PHP 应用的执行效率。JIT 编译器是 OPcache 的一个扩展,它可以将 PHP 脚本在运行时编译成机器码,而不是像传统的 OPcache 那样仅缓存预编译的字节码。这种方法可以在某些情况下显著提高性能,特别是在 CPU 密集型的应用中。 JIT 的工作原理 传统的 OPcache 通过缓存 PHP 脚本的预编译字节码来减少脚本的编译时间。这些字节码仍然需要通过 Zend 引擎的虚拟机来解释执行。而 JIT 编译器则进一步将这些字节码编译成直接可以在硬件上执行的机器码。这意味着减少了虚拟机执行指令的开销,从而在理论上可以提供更高的执行速度。 JIT 的配置和使用 在 php.ini 文件中,可以通过以下指令来启用和配置 JIT 编译: opcache.jit_buffer_size:为 JIT 编译器分配的内存大小。非零值启用 JIT 功能,例如 opcache.jit_buffer_size=100M 分配了 100MB 的内存给 JIT 编译器。 opcache.jit:控制 JIT 编译的触发方式和编译程度。它可以设置为不同的值,代表不同的 JIT 编译策略,包括“tracing”和“function”模式,以及它们的不同触发级别。 PHP 官方文档提供了多种预设的 JIT 配置模式,例如: opcache.jit=tracing:启用“tracing”模式,这是一种更积极的 JIT 编译策略,旨在为长时间运行的脚本提供最大化的性能提升。 opcache.jit=function:启用“function”模式,这是一种较为保守的编译策略,适用于普通的 web 请求处理。 JIT 的性能影响 JIT 的性能提升效果依赖于具体的应用场景。对于大多数传统的 web 应用来说,JIT 可能带来的性能提升有限,因为这些应用的瓶颈通常在于数据库访问、网络延迟等,而不是 CPU 的计算能力。然而,对于计算密集型的应用,如图像处理、大数据分析等,JIT 可以提供显著的性能提升。 结论 OPcache JIT 是 PHP 性能优化的一个重要工具,特别是在 PHP 8.0 及更高版本中。它通过将 PHP 脚本编译成机器码,减少了运行时的解释执行开销,有潜力显著提升 PHP 应用的执行速度。不过,它的实际效果需要根据应用的具体场景和负载模式进行评估。正确配置和测试 JIT 对于充分利用其性能优势至关重要。
  11. 成为一名C++资深开发者,需要掌握广泛的知识和技能,不仅包括C++语言本身的深入理解,还包括软件设计、性能优化、跨平台开发等方面的知识。以下是一些关键领域和推荐的学习资源: 关键领域 C++语言基础: 掌握C++的基本语法、数据类型、指针和引用、面向对象编程等。 C++标准库: 熟悉STL(标准模板库),包括容器、算法、迭代器等,并了解C++11及之后版本引入的新特性。 高级特性: 掌握模板编程、泛型编程、异常处理、智能指针等高级特性。 并发编程: 了解多线程编程、同步机制、C++11中引入的线程库。 性能优化: 掌握代码优化技巧,包括内存管理、编译器优化选项、性能分析工具等。 软件设计和架构: 理解设计模式、软件架构原则、依赖注入、单元测试和测试驱动开发等。 跨平台开发: 学习如何在不同的操作系统(如Windows、Linux、macOS)上进行开发和调试。 学习资源 书籍: 《C++ Primer》(Stanley B. Lippman, Josée Lajoie, and Barbara E. Moo): 适合初学者和中级开发者深入学习C++。 《Effective C++》(Scott Meyers): 提供了改善程序和设计质量的55个具体做法。 《More Effective C++》(Scott Meyers): 继续深入探讨C++编程的35个具体做法。 《C++ Concurrency in Action》(Anthony Williams): 专门讲解C++中的并发和多线程编程。 在线课程和教程: C++教程 - 菜鸟教程: 提供C++基础知识的教程。 Learn C++: 一站式学习网站,覆盖从基础到高级的所有内容。 Pluralsight C++ Path: 提供从初级到高级的C++学习路径。 官方文档和标准: C++ Reference: 提供了C++标准库的参考文档,包括最新的C++20标准。 ISO C++: 国际标准化组织(ISO)C++委员会的官方网站,提供标准文档和相关新闻。 社区和论坛: Stack Overflow: 在这里你可以找到大量的C++相关问题和解答。 Reddit C++ Community: 一个活跃的C++社区,可以获取最新资讯和讨论。 成为一名资深C++开发者是一个持续学习和实践的过程。除了阅读书籍和在线资源,积极参与项目开发、代码审查和社区交流也是不可或缺的部分。通过实际应用中遇到的问题学习和成长
  12. 现在主流的利用文字生成图像的技术主要基于深度学习,特别是生成对抗网络(GAN)和变分自编码器(VAE)等模型。这些技术能够理解文字输入的内容,并将这些理解转换成相应的图像输出。其中最著名的项目可能是OpenAI的DALL·E系列,以及谷歌的Imaginaire等。 要自己本地搭建一套文字生成图像的系统,理论上是可行的,但需要考虑以下几个方面: 硬件要求: 这类模型通常需要强大的计算能力,尤其是需要高性能的GPU。对于高质量的图像生成,可能需要多个高端GPU并行计算。 软件和框架: 需要熟练掌握深度学习框架,如TensorFlow或PyTorch,以及对应的编程语言(通常是Python)。此外,对GAN、VAE等模型有深入理解也是必要的。 数据集: 训练这类模型需要大量的文本-图像配对数据集。这些数据集需要经过精心准备和预处理,以确保模型能够学习到文本和图像之间的关联。 时间和耐心: 训练这样的模型需要大量的时间,尤其是在个人硬件设施上。此外,调整模型参数以达到理想的生成效果需要大量的实验和耐心。 如果你对这方面有深厚的兴趣,并且愿意投入时间和资源去实现,可以尝试以下步骤开始: 学习和准备: 首先,确保你有足够的深度学习知识,特别是对GAN或VAE等生成模型的理解。 搭建环境: 准备好硬件环境,并安装必要的深度学习框架和库。 获取数据集: 寻找或创建适合的文本-图像配对数据集。 模型训练: 选择或开发适合的模型架构,并开始训练。这个过程可能需要不断地调整和优化。 评估和优化: 训练完成后,评估模型的效果,并根据需要进行调整和优化。 需要注意的是,即使是专业的研究团队和公司,要开发出高质量的文字生成图像模型也是一项挑战。因此,如果你是初学者,可以考虑先从理解和使用现有的开源模型和工具开始,逐步深入到自己搭建系统的阶段。
  13. 1. 使用C++和OpenSSL生成密钥对 下面是一个简单的C++示例代码,展示如何使用OpenSSL库生成RSA密钥对,并将其保存到文件中 #include <openssl/pem.h> #include <openssl/rsa.h> #include <openssl/evp.h> int main() { int ret = 0; RSA *r = NULL; BIGNUM *bne = NULL; BIO *bp_public = NULL, *bp_private = NULL; int bits = 2048; unsigned long e = RSA_F4; // 1. 生成RSA密钥 bne = BN_new(); ret = BN_set_word(bne, e); if(ret != 1){ goto free_all; } r = RSA_new(); ret = RSA_generate_key_ex(r, bits, bne, NULL); if(ret != 1){ goto free_all; } // 2. 保存公钥 bp_public = BIO_new_file("public.pem", "w+"); ret = PEM_write_bio_RSAPublicKey(bp_public, r); if(ret != 1){ goto free_all; } // 3. 保存私钥 bp_private = BIO_new_file("private.pem", "w+"); ret = PEM_write_bio_RSAPrivateKey(bp_private, r, NULL, NULL, 0, NULL, NULL); // 结束处理 free_all: BIO_free_all(bp_public); BIO_free_all(bp_private); RSA_free(r); BN_free(bne); return ret == 1; } 这段代码会生成一对2048位的RSA密钥,并分别保存为public.pem和private.pem文件。 确保您已安装OpenSSL并在编译时链接到OpenSSL库。一个典型的编译命令可能如下: g++ -o generate_keys generate_keys.cpp -lssl -lcrypto 2. 在PHP中使用密钥对加密和解密 接下来是PHP代码示例,展示如何使用上面生成的密钥对进行加密和解密操作。 <?php // 加载公钥 $publicKey = file_get_contents('public.pem'); $privateKey = file_get_contents('private.pem'); // 要加密的数据 $data = "Hello, OpenSSL!"; // 使用公钥加密 openssl_public_encrypt($data, $encrypted, $publicKey); // 加密后的内容通常是乱码,可以进行base64编码 $encrypted = base64_encode($encrypted); echo "Encrypted: $encrypted\n"; // 使用私钥解密 openssl_private_decrypt(base64_decode($encrypted), $decrypted, $privateKey); echo "Decrypted: $decrypted\n"; ?> 这段PHP代码首先加载了公钥和私钥文件,然后使用公钥加密了一段字符串,最后使用私钥对这段加密的字符串进行了解密。 请确保在运行这些PHP代码之前,你已经运行了C++代码以生成密钥对,并且PHP环境已正确安装且支持OpenSSL。
  14. 墨香年少

    java加密

    在Java中,你可以使用Java Cryptography Extension (JCE) 提供的API来实现HMAC-SHA256签名的生成和验证。下面是如何在Java中进行加密签名和验证的示例。 Java 示例 生成签名: import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; public class SignatureExample { public static String generateSignature(String data, String secretKey) throws Exception { // 使用HmacSHA256算法初始化Mac对象 Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); SecretKeySpec secret_key = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256"); sha256_HMAC.init(secret_key); // 对数据进行加密 byte[] hash = sha256_HMAC.doFinal(data.getBytes()); // 将加密后的字节数组转换为字符串 String signature = Base64.getEncoder().encodeToString(hash); return signature; } public static void main(String[] args) { String secretKey = "your_secret_key"; String data = "data_to_sign"; try { String signature = generateSignature(data, secretKey); System.out.println("Signature: " + signature); } catch (Exception e) { e.printStackTrace(); } } } 验证签名: 验证签名时,你将使用相同的generateSignature方法生成签名,并将其与接收到的签名进行比较。如果两者一致,说明签名验证通过。 public class VerifySignature { // 假设receivedSignature是你从客户端接收到的签名字符串 public static boolean verifySignature(String data, String secretKey, String receivedSignature) { try { String generatedSignature = SignatureExample.generateSignature(data, secretKey); // 比较生成的签名和接收到的签名 return generatedSignature.equals(receivedSignature); } catch (Exception e) { e.printStackTrace(); return false; } } public static void main(String[] args) { String secretKey = "your_secret_key"; String data = "data_to_sign"; String receivedSignature = "the_signature_you_received"; boolean isValid = verifySignature(data, secretKey, receivedSignature); System.out.println("Is signature valid? " + isValid); } } 在这个示例中,generateSignature方法使用HmacSHA256算法对数据进行签名,并将签名结果编码为Base64字符串。verifySignature方法则用于验证接收到的签名是否与期望的签名匹配。 请确保在实际应用中,密钥secretKey保持安全,不要硬编码在代码中或者暴露给客户端。密钥应该妥善保管,只有服务器和授权的客户端知道。
  15. 设计安全的Web API加密签名方式通常涉及以下几个步骤: 选择加密算法:常见的有HMAC (Hash-based Message Authentication Code)、RSA、SHA-256等。HMAC是一种广泛使用的安全协议,因为它提供了一种验证消息完整性和身份验证的方式。 生成签名:使用服务器和客户端共享的密钥,对请求中的重要信息(如请求方法、URI、时间戳和请求体)进行加密,生成唯一的签名。 验证签名:服务器接收到请求后,使用相同的密钥和算法对请求进行加密,并将结果与请求中的签名进行比较。如果匹配,则认为请求是合法的。 以下是PHP和C++中实现API加密签名的示例。 PHP 示例 假设我们使用HMAC-SHA256算法生成和验证签名。 生成签名: <?php // 服务器和客户端共享的密钥 $secretKey = 'your_secret_key'; // 待签名的数据 $data = 'data_to_sign'; // 生成签名 $signature = hash_hmac('sha256', $data, $secretKey); echo "Signature: " . $signature; ?> 验证签名: <?php // 接收到的数据和签名 $receivedData = 'data_to_sign'; $receivedSignature = 'received_signature'; // 服务器端的密钥 $secretKey = 'your_secret_key'; // 使用相同的方法生成签名 $validSignature = hash_hmac('sha256', $receivedData, $secretKey); // 验证签名 if(hash_equals($validSignature, $receivedSignature)) { echo "Valid signature"; } else { echo "Invalid signature"; } ?> C++ 示例 在C++中,你可以使用OpenSSL库来实现HMAC加密。 首先,确保你已经安装了OpenSSL库。 生成签名: #include <openssl/hmac.h> #include <iostream> #include <iomanip> #include <sstream> std::string generateSignature(const std::string &data, const std::string &key) { unsigned char* digest; digest = HMAC(EVP_sha256(), key.c_str(), key.length(), (unsigned char*)data.c_str(), data.length(), NULL, NULL); std::stringstream ss; for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) { ss << std::hex << std::setw(2) << std::setfill('0') << (int)digest[i]; } return ss.str(); } int main() { std::string key = "your_secret_key"; std::string data = "data_to_sign"; std::string signature = generateSignature(data, key); std::cout << "Signature: " << signature << std::endl; } 验证签名与生成签名类似,你需要将接收到的签名与你自己生成的签名进行比较。 请注意,这里的C++示例需要链接OpenSSL库。如果你使用的是g++,可以通过添加-lcrypto选项来链接它,例如: g++ your_file.cpp -o your_program -lcrypto 这些示例展示了如何在PHP和C++中使用HMAC-SHA256算法来生成和验证API请求的签名。在实际应用中,你可能还需要考虑添加时间戳、随机数等额外信息到签名中,以进一步增强安全性。
  16. 要实现这样一个复杂的系统,我们需要整合多个组件,包括线程池、任务队列、MySQL连接池以及网络请求处理。在Debian系统下,我们通常使用C++标准库(C++11及以上)来实现线程池和任务队列,使用MySQL Connector/C++库来管理MySQL连接池,以及使用libcurl库来处理HTTP请求。下面,我将提供一个基本框架和示例代码,分为几个部分来实现这个系统。 1. 库的依赖 C++标准库: 用于线程池和任务队列。 MySQL Connector/C++: 用于MySQL连接池。 libcurl: 用于处理HTTP请求。 在Debian系统上,你可以使用apt-get来安装这些库的开发版本: sudo apt-get update sudo apt-get install libmysqlcppconn-dev libcurl4-openssl-dev 2. 线程池和任务队列 首先,我们需要实现线程池和任务队列。线程池负责管理线程,任务队列用于存放待执行的任务。 // ThreadPool.h #ifndef THREADPOOL_H #define THREADPOOL_H #include <vector> #include <queue> #include <memory> #include <mutex> #include <condition_variable> #include <future> #include <functional> #include <stdexcept> class ThreadPool { public: ThreadPool(size_t); template<class F, class... Args> auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type>; ~ThreadPool(); private: // 需要跟踪的工作线程 std::vector< std::thread > workers; // 任务队列 std::queue< std::function<void()> > tasks; // 同步 std::mutex queue_mutex; std::condition_variable condition; bool stop; }; #endif // ThreadPool.cpp #include "ThreadPool.h" // 构造函数启动一定数量的工作线程 ThreadPool::ThreadPool(size_t threads) : stop(false) { for(size_t i = 0;i<threads;++i) workers.emplace_back( [this] { for(;;) { std::function<void()> task; { std::unique_lock<std::mutex> lock(this->queue_mutex); this->condition.wait(lock, [this]{ return this->stop || !this->tasks.empty(); }); if(this->stop && this->tasks.empty()) return; task = std::move(this->tasks.front()); this->tasks.pop(); } task(); } } ); } // 添加新的工作项到线程池中 template<class F, class... Args> auto ThreadPool::enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type> { using return_type = typename std::result_of<F(Args...)>::type; auto task = std::make_shared< std::packaged_task<return_type()> >( std::bind(std::forward<F>(f), std::forward<Args>(args)...) ); std::future<return_type> res = task->get_future(); { std::unique_lock<std::mutex> lock(queue_mutex); // 不允许在停止ThreadPool后加入新任务 if(stop) throw std::runtime_error("enqueue on stopped ThreadPool"); tasks.emplace([task](){ (*task)(); }); } condition.notify_one(); return res; } // 析构函数 ThreadPool::~ThreadPool() { { std::unique_lock<std::mutex> lock(queue_mutex); stop = true; } condition.notify_all(); for(std::thread &worker: workers) worker.join(); } // MySQLPool.h #ifndef MYSQLPOOL_H #define MYSQLPOOL_H #include <mysql_driver.h> #include <mysql_connection.h> #include <cppconn/exception.h> #include <cppconn/statement.h> #include <cppconn/resultset.h> #include <cppconn/prepared_statement.h> #include <queue> #include <string> #include <mutex> #include <condition_variable> class MySQLPool { // 实现细节略 }; #endif 4. HTTP请求和任务处理 使用libcurl库来处理HTTP请求。你可以为每个任务定义一个函数,该函数执行HTTP请求并处理结果。 // HttpClient.h #ifndef HTTPCLIENT_H #define HTTPCLIENT_H #include <curl/curl.h> #include <string> class HttpClient { public: HttpClient(); ~HttpClient(); std::string getRequest(const std::string& url); private: CURL *curl; // 实现细节略 }; #endif 在HttpClient类中,你可以实现一个getRequest方法,该方法接收一个URL,执行HTTP GET请求,并返回响应。 5. 组合使用 将这些组件结合起来,你可以创建一个系统,该系统从任务队列中取出任务,使用线程池并发执行这些任务,每个任务可以是一个HTTP请求或数据库操作。操作完成后,可以根据需要处理结果。 请注意,这里提供的代码仅是一个起点。实际项目中,你可能需要对异常处理、连接重试逻辑、以及性能优化等方面进行更深入的开发和调整。对于更完整和复杂的系统,建议查阅相关文档并参考现有的开源项目。
  17. #include <iostream> #include <Windows.h> #include <iphlpapi.h> #include <lmcons.h> #include <Psapi.h> #pragma comment(lib, "IPHLPAPI.lib") #pragma comment(lib, "Psapi.lib") void GetSystemInfo(); int CountBits(DWORD bits); void GetSystemInfo() { // 获取计算机名称 wchar_t computerName[MAX_COMPUTERNAME_LENGTH + 1]; DWORD size = sizeof(computerName) / sizeof(computerName[0]); if (GetComputerName(computerName, &size)) { wprintf(L"计算机名称: %s\n", computerName); } // 获取IP地址和MAC地址 PIP_ADAPTER_INFO adapterInfo = NULL; ULONG bufferSize = 0; if (GetAdaptersInfo(adapterInfo, &bufferSize) == ERROR_BUFFER_OVERFLOW) { adapterInfo = (IP_ADAPTER_INFO*)malloc(bufferSize); if (GetAdaptersInfo(adapterInfo, &bufferSize) == NO_ERROR) { wprintf(L"IP地址: %s\n", adapterInfo->IpAddressList.IpAddress.String); wprintf(L"MAC地址: %02X-%02X-%02X-%02X-%02X-%02X\n", adapterInfo->Address[0], adapterInfo->Address[1], adapterInfo->Address[2], adapterInfo->Address[3], adapterInfo->Address[4], adapterInfo->Address[5]); } free(adapterInfo); } // 获取内存大小 MEMORYSTATUSEX memoryStatus; memoryStatus.dwLength = sizeof(memoryStatus); if (GlobalMemoryStatusEx(&memoryStatus)) { wprintf(L"内存大小: %I64u MB\n", memoryStatus.ullTotalPhys / (1024 * 1024)); } // 获取磁盘信息 DWORD drives = GetLogicalDrives(); wprintf(L"磁盘数量: %d\n", CountBits(drives)); ULARGE_INTEGER freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes; if (GetDiskFreeSpaceEx(NULL, &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes)) { wprintf(L"磁盘空间: %I64u MB\n", totalNumberOfBytes.QuadPart / (1024 * 1024)); } // 获取操作系统信息 OSVERSIONINFOEX osInfo; ZeroMemory(&osInfo, sizeof(OSVERSIONINFOEX)); osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); DWORDLONG conditionMask = 0; VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); if (VerifyVersionInfo(&osInfo, VER_MAJORVERSION | VER_MINORVERSION, conditionMask)) { wprintf(L"操作系统: %d.%d\n", osInfo.dwMajorVersion, osInfo.dwMinorVersion); } } int CountBits(DWORD bits) { int count = 0; while (bits) { count += bits & 1; bits >>= 1; } return count; } int main() { GetSystemInfo(); return 0; }
  18. package main import ( "database/sql" "fmt" "log" "sync" "time" _ "github.com/go-sql-driver/mysql" ) // Task represents a task that can be executed by the worker type Task struct { Query string MySQLConn *sql.DB } // WorkerPool represents a simple worker pool type WorkerPool struct { WorkerCount int JobQueue chan Task WaitGroup sync.WaitGroup } // NewWorkerPool creates a new WorkerPool func NewWorkerPool(workerCount int) *WorkerPool { return &WorkerPool{ WorkerCount: workerCount, JobQueue: make(chan Task, workerCount), } } // Start initializes and starts the worker pool func (wp *WorkerPool) Start() { for i := 0; i < wp.WorkerCount; i++ { go wp.worker() } } // Enqueue adds a task to the job queue func (wp *WorkerPool) Enqueue(task Task) { wp.WaitGroup.Add(1) wp.JobQueue <- task } // StopAndWait stops the worker pool and waits for all tasks to complete func (wp *WorkerPool) StopAndWait() { close(wp.JobQueue) wp.WaitGroup.Wait() } // worker is the actual worker that executes tasks func (wp *WorkerPool) worker() { defer wp.WaitGroup.Done() for task := range wp.JobQueue { if err := task.Execute(); err != nil { log.Printf("Error executing task: %v", err) } } } // Execute executes the task (query) on the MySQL connection func (t Task) Execute() error { _, err := t.MySQLConn.Exec(t.Query) return err } // MySQLConnectionPool represents a simple MySQL connection pool type MySQLConnectionPool struct { MaxConnections int connections chan *sql.DB mu sync.Mutex } // NewMySQLConnectionPool creates a new MySQLConnectionPool func NewMySQLConnectionPool(maxConnections int, dataSourceName string) (*MySQLConnectionPool, error) { pool := &MySQLConnectionPool{ MaxConnections: maxConnections, connections: make(chan *sql.DB, maxConnections), } for i := 0; i < maxConnections; i++ { conn, err := sql.Open("mysql", dataSourceName) if err != nil { return nil, fmt.Errorf("failed to open MySQL connection: %v", err) } pool.connections <- conn } return pool, nil } // GetConnection retrieves a connection from the pool func (p *MySQLConnectionPool) GetConnection() *sql.DB { p.mu.Lock() defer p.mu.Unlock() return <-p.connections } // ReleaseConnection releases a connection back to the pool func (p *MySQLConnectionPool) ReleaseConnection(conn *sql.DB) { p.mu.Lock() defer p.mu.Unlock() p.connections <- conn } func main() { // Replace the following MySQL connection details dataSourceName := "root:password@tcp(localhost:3306)/database" // Create MySQL connection pool mysqlPool, err := NewMySQLConnectionPool(5, dataSourceName) if err != nil { log.Fatalf("Failed to create MySQL connection pool: %v", err) } // Create and start worker pool workerPool := NewWorkerPool(4) workerPool.Start() // Use worker pool to execute tasks for i := 0; i < 10; i++ { query := fmt.Sprintf("INSERT INTO table_name (column1, column2) VALUES (%d, 'value')", i) conn := mysqlPool.GetConnection() task := Task{Query: query, MySQLConn: conn} workerPool.Enqueue(task) mysqlPool.ReleaseConnection(conn) } // Stop worker pool and wait for tasks to complete workerPool.StopAndWait() }
  19. ThreadPool.h #pragma once #include <iostream> #include <thread> #include <vector> #include <queue> #include <mutex> #include <condition_variable> #include <functional> #include <stdexcept> #include <future> class ThreadPool { public: ThreadPool(size_t threads); template<class F, class... Args> auto enqueue(F&& f, Args&&... args) -> std::future<decltype(f(args...))>; ~ThreadPool(); private: std::vector<std::thread> workers; std::queue<std::function<void()>> tasks; std::mutex queue_mutex; std::condition_variable condition; bool stop; }; ThreadPool.cpp #include "ThreadPool.h" inline ThreadPool::ThreadPool(size_t threads) : stop(false) { for (size_t i = 0; i < threads; ++i) { workers.emplace_back( [this] { for (;;) { std::function<void()> task; { std::unique_lock<std::mutex> lock(this->queue_mutex); this->condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); }); if (this->stop && this->tasks.empty()) return; task = std::move(this->tasks.front()); this->tasks.pop(); } task(); } } ); } } template<class F, class... Args> auto ThreadPool::enqueue(F&& f, Args&&... args) -> std::future<decltype(f(args...))> { using return_type = decltype(f(args...)); auto task = std::make_shared<std::packaged_task<return_type()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...)); std::future<return_type> res = task->get_future(); { std::unique_lock<std::mutex> lock(queue_mutex); if (stop) throw std::runtime_error("enqueue on stopped ThreadPool"); tasks.emplace([task]() { (*task)(); }); } condition.notify_one(); return res; } inline ThreadPool::~ThreadPool() { { std::unique_lock<std::mutex> lock(queue_mutex); stop = true; } condition.notify_all(); for (std::thread &worker : workers) worker.join(); } MysqlConnectionPool.h #pragma once #include <iostream> #include <vector> #include <mutex> #include <mysql/mysql.h> class MysqlConnectionPool { public: MysqlConnectionPool(const std::string& host, const std::string& user, const std::string& password, const std::string& database, unsigned int port, size_t pool_size); ~MysqlConnectionPool(); MYSQL* getConnection(); void releaseConnection(MYSQL* conn); private: std::string host; std::string user; std::string password; std::string database; unsigned int port; size_t pool_size; std::vector<MYSQL*> connections; std::mutex pool_mutex; }; MysqlConnectionPool.cpp #include "MysqlConnectionPool.h" inline MysqlConnectionPool::MysqlConnectionPool(const std::string& host, const std::string& user, const std::string& password, const std::string& database, unsigned int port, size_t pool_size) : host(host), user(user), password(password), database(database), port(port), pool_size(pool_size) { for (size_t i = 0; i < pool_size; ++i) { MYSQL* conn = mysql_init(nullptr); if (!conn) { throw std::runtime_error("mysql_init failed"); } if (!mysql_real_connect(conn, host.c_str(), user.c_str(), password.c_str(), database.c_str(), port, nullptr, 0)) { throw std::runtime_error("mysql_real_connect failed"); } connections.push_back(conn); } } inline MysqlConnectionPool::~MysqlConnectionPool() { for (MYSQL* conn : connections) { mysql_close(conn); } } inline MYSQL* MysqlConnectionPool::getConnection() { std::unique_lock<std::mutex> lock(pool_mutex); if (connections.empty()) { throw std::runtime_error("No available connections in the pool"); } MYSQL* conn = connections.back(); connections.pop_back(); return conn; } inline void MysqlConnectionPool::releaseConnection(MYSQL* conn) { std::unique_lock<std::mutex> lock(pool_mutex); connections.push_back(conn); } Task.h #pragma once #include <string> #include <mysql/mysql.h> class Task { public: Task(const std::string& query, MYSQL* mysql_conn); void operator()(); private: std::string query; MYSQL* mysql_conn; }; Task.cpp #include "Task.h" inline Task::Task(const std::string& query, MYSQL* mysql_conn) : query(query), mysql_conn(mysql_conn) {} inline void Task::operator()() { if (mysql_query(mysql_conn, query.c_str()) != 0) { std::cerr << "MySQL query error: " << mysql_error(mysql_conn) << std::endl; } } 主程序 #include "ThreadPool.h" #include "MysqlConnectionPool.h" #include "Task.h" int main() { try { MysqlConnectionPool mysqlPool("localhost", "root", "password", "database", 3306, 5); ThreadPool pool(4); for (int i = 0; i < 10; ++i) { std::string query = "INSERT INTO table_name (column1, column2) VALUES (" + std::to_string(i) + ", 'value')"; MYSQL* conn = mysqlPool.getConnection(); pool.enqueue(Task(query, conn)); mysqlPool.releaseConnection(conn); } } catch (const std::exception& e) { std::cerr << "Exception: " << e.what() << std::endl; } return 0; }
  20. 使用`yum`命令安装`ntpdate`工具:`yum install ntpdate`。 通过`ntpdate`命令同步时间到指定的服务器,例如`ntpdate cn.pool.ntp.org`。
  21. <?php namespace App\Controller; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\HttpKernel\KernelInterface; class DefaultController extends BaseController { private $environment; public function __construct(KernelInterface $kernel) { $this->environment = $kernel->getEnvironment(); } #[Route('/', name: 'app_default')] public function index(){return $this->_render();} private function _render() { var_dump( $this->environment ); die(); } } 获取.env中的 APP_ENV
  22. controller中使用 var_dump($this->getParameter('kernel.debug')); 来获取.env中的 APP_DEBUG
  23. php排序 function ascii_params($params = array()) { if (!empty($params)) { $p = ksort($params); if ($p) { $str = ''; foreach ($params as $k => $val) { $str .= $k . '=' . $val . '&'; } $strs = rtrim($str, '&'); return $strs; } } return ''; } function sign($data, $key) { $str = $this->ascii_params($data); $signature = ""; if (function_exists('hash_hmac')) { $signature = base64_encode(hash_hmac("sha1", $str, $key, true)); } else { $blocksize = 64; $hashfunc = 'sha1'; if (strlen($key) > $blocksize) { $key = pack('H*', $hashfunc($key)); } $key = str_pad($key, $blocksize, chr(0x00)); $ipad = str_repeat(chr(0x36), $blocksize); $opad = str_repeat(chr(0x5c), $blocksize); $hmac = pack('H*', $hashfunc(($key ^ $opad) . pack('H*', $hashfunc(($key ^ $ipad) . $str)))); $signature = base64_encode($hmac); } return $signature; } import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Base64; import java.util.UUID; import java.io.UnsupportedEncodingException; public class HmacUtil { public static final String HMAC_SHA1 = "HmacSHA1"; public static final String HMAC_MD5 = "HmacMD5"; public static final String HMAC_SHA256 = "HmacSHA256"; public static final String HMAC_SHA512 = "HmacSHA512"; public static String encrypt(String input, String key, String algorithm) { String cipher = ""; try { byte[] data = key.getBytes(StandardCharsets.UTF_8); SecretKey secretKey = new SecretKeySpec(data, algorithm); Mac mac = Mac.getInstance(algorithm); mac.init(secretKey); byte[] text = input.getBytes(StandardCharsets.UTF_8); byte[] encryptByte = mac.doFinal(text); cipher = Base64.getEncoder().encodeToString(encryptByte); } catch (NoSuchAlgorithmException | InvalidKeyException e) { e.printStackTrace(); } return cipher; } public static String bytesToHexStr(byte[] bytes) { StringBuilder hexStr = new StringBuilder(); for (byte b : bytes) { String hex = Integer.toHexString(b & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } hexStr.append(hex); } return hexStr.toString(); } public static void main(String[] args) { String valSha1 = HmacUtil.encrypt("amount=100&appid=123456&notify_url=http://www.google.com&order_no=abcd", "keykeykey", HmacUtil.HMAC_SHA1); System.out.println(valSha1); //MM2yDl0IpBi8INXKDUSRba8cuVE= } } go: package main import ( "crypto/hmac" "crypto/sha1" "encoding/base64" "fmt" ) func main() { fmt.Println(GetSignature("amount=60.00&appid=111&order_no=222&timestamp=333&version=2.0", "444")) } func GetSignature(input, key string) string { key_for_sign := []byte(key) h := hmac.New(sha1.New, key_for_sign) h.Write([]byte(input)) return base64.StdEncoding.EncodeToString(h.Sum(nil)) }
  24. private.pem内容如下: -----BEGIN ENCRYPTED PRIVATE KEY----- MIIFNTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQOK8dtKgkLYhVrCvT H1sApwICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEAQIEEIHzRTJuFe9RCFJh 7VyNprgEggTQiHManjAoSGJrD2KXnom5lirDcdNpUBwzWB0QYgTGrHSm9Frzw0za ugfvHoHZ/joH9rInn5rrpL5Z7SHrcJp9wOK4QZd7rB+a4DeY5Rvwe6AyikEXsug5 5SZqK/7vmkbzxmgxt6LlaX99vyDaxqHb79HF7IGc7jz9vIoILV5jQeTNfVUn/kYS RX1l59KwVOkNkJR2nyphYrT9Adu5xmOigKYIEU7R6TNSELWZccMYTvRkc3tUggNo XDxEkB+/+Fzo+A+oEPj9aNesZbZLCZv2EBP7tlVM/28ScJulRGgZ5zK/roMMzgb2 bMjQ432WseKcyuhrwo0SCmJTxKEzISLqITokVjqPL9gZ1/376ZmcoXWFRbKaj+wf Le10OtHq1OvQMjQE+kmlqDtjVYbm6/+1GXIkbl5sitU/alc3dwiR1DhINOehWTAF qbfNqBp2hi5vn/n3c8ZCZgm4vWnW6WjYOJtEJSzDJKARubgIEKyuht9zFj2w8Ans EnL5/qiJ1HirbWXayRHHGMR0y9UpRCPuUL08q8FxJphYypvh+p/k1+FaxhY5DJYL 1Nj01NbW5T0FsWJzn9oh7qSFRheLQ2udfF0f2Fpr3yd53py0vhaa14l41x/wVZ8o 8uq5+4O7joJQ/yiXU90Gk2m3pJ02jWE2gx4wYbI34RBhfzIEkuROSVGcCfaeUwyc UHXnrmWY2pVbazv7UH7Bcbgh6hj4I+9MUJYpGZ59sIc3AcyMNMtdqE08RhQ4YSc4 RJxNLtcYxXQGajYrRqIQZCvgt8iNbXXCQBRbfsPzzNM3MTsyp4p1fI1wfWzvXwFK o10HxfVpJ9FVGK4Zj4T8Fjd69dNryZqLHzJAZeGp0APZNcK/Y5xtkiqTtJxdLm9T iLGc1/6+JzGpJuyxNwpP3MKEhpRl7Xfefv5RpV5YwRmhPlroarD9Hks4/6nsW0wH +ygyT/jNKRwR2/QSpvOSMoQW+TF8MrAa+RXoWebp3QSLO0PGf2gWrsKhfeUelYO8 1TqoxVY3eOJ07h1elbF5Dq2gl+YCvP3L8HRDNlxo3h5ukYnMIeakv8IJyPzpYi0U SqzqY1BQKIWCf8plZahyKAH9+GLVF43/x1f3AOWNR1fFX0eVC3WLO1O5WPHPDhuI sCfeu4KuZWBMpL8/HIE7bSVptyFZrMJktNYZz5pGxy9wikXm4jdMdLHmCrzp/hor 769zMv6xCdWFcofnHy74U4U9dTnLnQf+pY+wLI1XjW0CyATC5WRBXZ76565gaXHj /cMWe1GWThttB9+aORkKr55X0IP9lKSHMmFKEBIwb+q0UL/CxLVbgk3PDTONxlni OGORtGFwr8B/FYhlI3QKDNBdYHPfv8FEJe4kNgdrLk1jvdeWvcaOtjbMvkys1wvn uO86WwECRk38dM2+LRJ8llqqEldlbSLHmWOjizc5WFPymyEahlA9EOIw72tMPrTe jXGKwZgEhkVTvi0jvlMY7lJDDQnqMou2ZxFH1MjOpST0lsU1lr2IcduOmRr8YF3k bmKYvvSe2Edld9oUjkUBVUVNWNYYaRe6v14GNn6xPC6rhx/xovD8n7aTMsM4JFLG pDaKXXWzDFaYMSHBY6THcSLwAdzqBeZJHoFh/qqAAPbgKA4+ShNOsmQ= -----END ENCRYPTED PRIVATE KEY-----
  25. public.pem内容如下: -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnk4CmS/EJxzEDZCwftdg QFWdk6R2WQaDLujY2b7q3eLR+b+8FJgwwFyLa96sJsmtp27lWMJKpX5kIjwG1091 aw6PNce7VZSa5RHWoTprcXWiyCQBR6CC+F3KsdsPDtIsWPSfXO9FA5UJC6G1Pofb xWSPBbayoRIlxcsGV+Gm6eAvZghZ+s79u0CGc9GNKG0SPFJuuxx4ixSWchQHd9Ow 2vzQuN7yJG4vo4sAhdUUTTBvTa8jhebDO2A8ViwEmVw5qkn3qXZfNCJohkf88gSb gYEmSsjHBBorL/7VSJ28nzejqtmFr9zQYExkHmCR/E0rGiW/CX0eOi4pEF7WDivv YwIDAQAB -----END PUBLIC KEY-----
×
×
  • Create New...

Important Information

注册必须使用2-8个中文汉字作为账号