自制虚拟机(C/C++)(一、分析语法和easyx运用,完整虚拟机实现)

网上对虚拟机的解释很多,其实本质就一句话

虚拟机就是机器语言解释器

我们今天要实现汇编语言解释器,下一次再加上ndisasm反汇编器就是真正虚拟机了

注:这里的虚拟机指的是VMware一类的,而不是JVM,python一样的高级语言解释器

上代码

#include <graphics.h>
#include <conio.h>
#include <windows.h>
#include <commdlg.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <unordered_map>
#include <algorithm>// 寄存器声明
unsigned char al = 0, ah = 0, bl = 0, bh = 0, cl = 0, ch = 0, dl = 0, dh = 0;
unsigned short ax = 0, bx = 0, cx = 0, dx = 0, sp = 0x8000, bp = 0;
unsigned int org = 0, end_times = 0, end_AA55 = 0;
bool ZF = false, CF = false, SF = false; // 标志寄存器// 标签和指令指针
std::unordered_map<std::string, size_t> labels;
size_t current_line = 0;
size_t new_current_line;
std::vector<std::string> program_lines;// 内存模拟
std::vector<unsigned char> memory(0x10000, 0); // 64KB内存// 图形输出参数
int textX = 0;
int textY = 48;
const int CHAR_WIDTH = 8;
const int LINE_HEIGHT = 16;
bool graphicsInitialized = false;// 指令解析错误枚举
enum class InstructionError {INVALID_OPCODE,INVALID_OPERAND,LABEL_NOT_FOUND,UNKNOWN_INTERRUPT,OTHER_ERROR
};// 输出错误信息到终端
void printError(const InstructionError& error, const std::string& details = "") {std::cerr << "ERROR: ";switch (error) {case InstructionError::INVALID_OPCODE:std::cerr << "无效的操作码";break;case InstructionError::INVALID_OPERAND:std::cerr << "无效的操作数";break;case InstructionError::LABEL_NOT_FOUND:std::cerr << "标签未找到";break;case InstructionError::UNKNOWN_INTERRUPT:std::cerr << "未知的中断号";break;case InstructionError::OTHER_ERROR:std::cerr << "其他错误";break;}if (!details.empty()) {std::cerr << " - " << details;}std::cerr << std::endl;
}int parseImmediate(const std::string& immediateStr) {std::string result;bool inQuote = false;char quoteChar = '\0';for (size_t i = 0; i < immediateStr.size(); ++i) {const char c = immediateStr[i];if (c == '\'' || c == '"') {if (!inQuote) {inQuote = true;quoteChar = c;result += c;} else if (c == quoteChar) {inQuote = false;result += c;} else {result += c;}} else if (inQuote) {// 直接将引号内的字符添加到结果中,包括空格result += c;} else if (!std::isspace(c)) {// 非空格且不在引号内,将字符添加到结果中result += c;} else if (i > 0 &&!std::isspace(result.back())) {// 如果前一个字符不是空格,添加当前字符以保留中间的空格result += c;}}// 去除结果字符串两端可能残留的空格while (!result.empty() && std::isspace(result.front())) {result.erase(result.begin());}while (!result.empty() && std::isspace(result.back())) {result.erase(result.length() - 1);}if (result.empty()) return 0;if (result.length() == 3 && result[0] == '\'' && result[2] == '\'') {return static_cast<int>(result[1]);}else if (result.find("0x") == 0) {try {return std::stoi(result.substr(2), nullptr, 16);} catch (const std::invalid_argument& e) {throw std::invalid_argument("无效的十六进制立即数:" + result);} catch (const std::out_of_range& e) {throw std::out_of_range("十六进制立即数超出范围:" + result);}}else if (result.back() == 'h') {try {return std::stoi(result.substr(0, result.length() - 1), nullptr, 16);} catch (const std::invalid_argument& e) {throw std::invalid_argument("无效的十六进制立即数(以h结尾):" + result);} catch (const std::out_of_range& e) {throw std::out_of_range("十六进制立即数(以h结尾)超出范围:" + result);}}else {try {return std::stoi(result);} catch (const std::invalid_argument& e) {throw std::invalid_argument("无效的立即数:" + result);} catch (const std::out_of_range& e) {throw std::out_of_range("立即数超出范围:" + result);}}
}std::unordered_map<std::string, unsigned char*>& createRegister8BitMap() {static std::unordered_map<std::string, unsigned char*> map = {{"al", &al}, {"ah", &ah}, {"bl", &bl}, {"bh", &bh},{"cl", &cl}, {"ch", &ch}, {"dl", &dl}, {"dh", &dh}};return map;
}std::unordered_map<std::string, unsigned short*>& createRegister16BitMap() {static std::unordered_map<std::string, unsigned short*> map = {{"ax", &ax}, {"bx", &bx}, {"cx", &cx}, {"dx", &dx},{"sp", &sp}, {"bp", &bp}};return map;
}void UpdateTextPosition() {textX += CHAR_WIDTH;if (textX > 620) {textX = 20;textY += LINE_HEIGHT;}if (textY + LINE_HEIGHT > 480) {cleardevice();textX = 0;textY = 0;}
}void MovInstruction(const std::string& line) {std::string processedLine = line;std::replace(processedLine.begin(), processedLine.end(), ',', ' ');std::istringstream iss(processedLine);std::string opcode, dest, src;iss >> opcode >> dest >> src;auto& reg8 = createRegister8BitMap();auto& reg16 = createRegister16BitMap();auto parseOperand = [&](const std::string& op) -> int {if (reg8.count(op)) return *reg8[op];if (reg16.count(op)) return *reg16[op];return parseImmediate(op);};int value = parseOperand(src);if (reg8.count(dest)) {*reg8[dest] = static_cast<unsigned char>(value);}else if (reg16.count(dest)) {*reg16[dest] = static_cast<unsigned short>(value);}
}void CmpInstruction(const std::string& line) {std::string processedLine = line;std::replace(processedLine.begin(), processedLine.end(), ',', ' ');std::istringstream iss(processedLine);std::string opcode, op1, op2;iss >> opcode >> op1 >> op2;auto& reg8 = createRegister8BitMap();auto& reg16 = createRegister16BitMap();auto parseOperand = [&](const std::string& op) -> int {if (reg8.count(op)) return *reg8[op];if (reg16.count(op)) return *reg16[op];return parseImmediate(op);};int val1 = parseOperand(op1);int val2 = parseOperand(op2);int result = val1 - val2;ZF = (result == 0);SF = (result < 0);CF = (static_cast<unsigned>(val1) < static_cast<unsigned>(val2));
}void JmpInstruction(const std::string& line) {std::istringstream iss(line);std::string opcode, label;iss >> opcode >> label;if (labels.count(label)) {new_current_line = labels[label];} else {printError(InstructionError::LABEL_NOT_FOUND, "JMP指令中的标签: " + label);}
}void JeInstruction(const std::string& line) {std::istringstream iss(line);std::string opcode, label;iss >> opcode >> label;if (ZF) {if (labels.count(label)) {new_current_line = labels[label];} else {printError(InstructionError::LABEL_NOT_FOUND, "JE指令中的标签: " + label);}} else {new_current_line = current_line + 1;}
}void JneInstruction(const std::string& line) {std::istringstream iss(line);std::string opcode, label;iss >> opcode >> label;if (!ZF) {if (labels.count(label)) {new_current_line = labels[label];} else {printError(InstructionError::LABEL_NOT_FOUND, "JNE指令中的标签: " + label);}} else {new_current_line = current_line + 1;}
}void PushInstruction(const std::string& line) {std::istringstream iss(line);std::string opcode, src;iss >> opcode >> src;auto& reg16 = createRegister16BitMap();unsigned short value = reg16.count(src)? *reg16[src] : parseImmediate(src);sp -= 2;memory[sp] = value & 0xFF;memory[sp + 1] = (value >> 8) & 0xFF;
}void PopInstruction(const std::string& line) {std::istringstream iss(line);std::string opcode, dest;iss >> opcode >> dest;auto& reg16 = createRegister16BitMap();if (reg16.count(dest)) {*reg16[dest] = memory[sp] | (memory[sp + 1] << 8);sp += 2;}
}void XorInstruction(const std::string& line) {std::string processedLine = line;std::replace(processedLine.begin(), processedLine.end(), ',', ' ');std::istringstream iss(processedLine);std::string opcode, dest, src;iss >> opcode >> dest >> src;auto& reg8 = createRegister8BitMap();auto& reg16 = createRegister16BitMap();auto parseOperand = [&](const std::string& op) -> int {if (reg8.count(op)) return *reg8[op];if (reg16.count(op)) return *reg16[op];return parseImmediate(op);};int val1 = parseOperand(dest);int val2 = parseOperand(src);int result = val1 ^ val2;if (reg8.count(dest)) {*reg8[dest] = static_cast<unsigned char>(result);}else if (reg16.count(dest)) {*reg16[dest] = static_cast<unsigned short>(result);}ZF = (result == 0);SF = (result < 0);CF = false;
}void PreprocessLabels() {for (size_t i = 0; i < program_lines.size(); ++i) {std::string line = program_lines[i];size_t colonPos = line.find(':');if (colonPos!= std::string::npos) {std::string label = line.substr(0, colonPos);labels[label] = i;program_lines[i] = line.substr(colonPos + 1);std::cout << "Label found: " << label << " at line " << i << std::endl;}}
}void IntInstruction(const std::string& line) {std::string processedLine = line;std::replace(processedLine.begin(), processedLine.end(), ',', ' ');std::istringstream iss(processedLine);std::string opcode, interrupt;iss >> opcode >> interrupt;if (interrupt == "0x10" || interrupt == "10h") {if (ah == 0x0E) {if (!graphicsInitialized) {initgraph(640, 480);setbkcolor(BLACK);cleardevice();settextcolor(CYAN);settextstyle(17, 0, _T("Courier New Bold"));graphicsInitialized = true;outtextxy(textX, 0, "VMwork BIOS (PCI)");outtextxy(textX, 16, "This VGA/VBE BIOS is released under the GNU LGPL");settextcolor(RGB(192, 192, 192));}// 处理特殊字符if (al == 0x0D) {outtextxy(textX, textY, " ");textY += LINE_HEIGHT;}else if (al == 0x0A) {outtextxy(textX, textY, " ");textX = 0;}else {char str[2] = { static_cast<char>(al) };outtextxy(textX, textY, " ");outtextxy(textX, textY, str);UpdateTextPosition();outtextxy(textX, textY, "|");}}if (ah == 0x02 && bh == 0) {textX = 0;textY = 0;}if (ax == 0x0600 && bx == 0x0700 && cx == 0 && dx == 0x184f) {cleardevice();}}else if (interrupt == "0x16" || interrupt == "16h") {if (ah == 0) {while (true) {if (_kbhit()) {al = _getch();break;}}}}else {printError(InstructionError::UNKNOWN_INTERRUPT, "未知的中断号: " + interrupt);}
}void CallInstruction(const std::string& line) {std::vector<std::string> tokens;std::istringstream iss(line);std::string token;while (iss >> token) {tokens.push_back(token);}if (tokens.size() < 2) {printError(InstructionError::INVALID_OPERAND, "CALL指令缺少操作数");return;}std::string label = tokens.back();if (labels.count(label)) {// 压入返回地址(当前行号的下一条指令)unsigned short return_line = current_line + 1;sp -= 2;memory[sp] = return_line & 0xFF;memory[sp + 1] = (return_line >> 8) & 0xFF;new_current_line = labels[label];} else {printError(InstructionError::LABEL_NOT_FOUND, "CALL指令中的标签: " + label);}
}void OrgInstruction(const std::string& line) {std::string processedLine = line;std::replace(processedLine.begin(), processedLine.end(), ',', ' ');std::istringstream iss(processedLine);std::string opcode, interrupt;iss >> opcode >> interrupt;if (interrupt == "0x7c00" || interrupt == "0x7C00") {org = 0x7c00;} else {printError(InstructionError::INVALID_OPERAND, "ORG指令的操作数无效: " + interrupt);}
}void TimesInstruction(const std::string& line) {std::string processedLine = line;std::replace(processedLine.begin(), processedLine.end(), ',', ' ');std::istringstream iss(processedLine);std::string opcode, interrupt;iss >> opcode >> interrupt;if (interrupt == "510-($-$$) db 0" || interrupt == "510-($-$$)") {end_times = 1;} else {printError(InstructionError::INVALID_OPERAND, "TIMES指令的操作数无效: " + interrupt);}
}void DwInstruction(const std::string& line) {std::string processedLine = line;std::replace(processedLine.begin(), processedLine.end(), ',', ' ');std::istringstream iss(processedLine);std::string opcode, interrupt;iss >> opcode >> interrupt;if (interrupt == "0xAA55" || interrupt == "0xaa55") {end_AA55 = 1;} else {printError(InstructionError::INVALID_OPERAND, "DW指令的操作数无效: " + interrupt);}
}int main(int argc, char* argv[]) {std::ifstream file;if (argc == 1) {OPENFILENAMEA ofn;char szFileName[MAX_PATH] = "";ZeroMemory(&ofn, sizeof(ofn));ofn.lStructSize = sizeof(ofn);ofn.hwndOwner = NULL;ofn.lpstrFilter = "所有文件 (*.*)\0*.*\0";ofn.lpstrFile = szFileName;ofn.nMaxFile = MAX_PATH;ofn.lpstrTitle = "请选择一个文件";ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST;if (GetOpenFileNameA(&ofn)) {file.open(szFileName);}else {if (graphicsInitialized) {closegraph();}return 0;}}else {file.open(argv[1]);}if (!file.is_open()) {std::cerr << "无法打开文件" << std::endl;if (graphicsInitialized) {closegraph();}return 1;}// 先将文件内容读取到 program_lines 中std::string line;while (std::getline(file, line)) {program_lines.push_back(line);}file.close();for (auto& progLine : program_lines) {for (size_t i = 0; i < progLine.size(); ++i) {if (i < progLine.size() - 2 && progLine[i] == '\'' && progLine[i + 1] ==' ' && progLine[i + 2] == '\'') {progLine[i]   = static_cast<char>(0x20);progLine.erase(i + 1, 2);  // 移除后面的空格和单引号}}}PreprocessLabels();// 重置指令指针和新的指令指针new_current_line = current_line;while (current_line < program_lines.size()) {std::istringstream iss(program_lines[current_line]);std::string opcode;iss >> opcode;if (opcode == "mov") MovInstruction(program_lines[current_line]);else if (opcode == "int") IntInstruction(program_lines[current_line]);else if (opcode == "org") OrgInstruction(program_lines[current_line]);else if (opcode == "times") TimesInstruction(program_lines[current_line]);else if (opcode == "dw") DwInstruction(program_lines[current_line]);else if (opcode == "cmp") CmpInstruction(program_lines[current_line]);else if (opcode == "jmp") JmpInstruction(program_lines[current_line]);else if (opcode == "je" || opcode == "jz") JeInstruction(program_lines[current_line]);else if (opcode == "jne" || opcode == "jnz") JneInstruction(program_lines[current_line]);else if (opcode == "push") PushInstruction(program_lines[current_line]);else if (opcode == "pop") PopInstruction(program_lines[current_line]);else if (opcode == "xor") XorInstruction(program_lines[current_line]);else if (opcode == "call") CallInstruction(program_lines[current_line]);else if (opcode != "\n" || opcode != "\t") std::cout << "warning:未识别的指令:" << opcode << "\n";if (opcode == "jmp" || opcode == "je" || opcode == "jne") {current_line = new_current_line;}else {current_line++;}new_current_line = current_line + 1; }
/*if (org!= 0x7c00 || end_times == 0 || end_AA55 == 0) {closegraph();}
*/if (graphicsInitialized) {_getch();//closegraph();}return 0;
}

编译:

g++ main.cpp -o VMwork -std=c++11 -leasyx -lcomdlg32

os.asm:

org 0x7c00start:mov bp, 0x8000mov sp, bp.print:mov ah, 0x0Emov al, 0x0Dint 0x10mov al, 0x0Aint 0x10mov al, 'H'int 0x10mov al, 'a'int 0x10mov al, 'n'int 0x10mov al, 'O'int 0x10mov al, 'S'int 0x10mov al, '>'int 0x10mov al, '>'int 0x10.wait_input:mov ah, 0x00int 0x16cmp al, 'c'je .check_input_c1cmp al, 'e'je .check_input_ecmp al, 'p'je .check_input_6.pycmp al, '.'je .check_input_pycmp al, 'l'je .check_input_lcmp al, 0x0Dje .bad_inputmov ah, 0x0Eint 0x10jmp .wait_input.check_input_l:mov ah, 0x0Eint 0x10mov ah, 0x00int 0x16mov ah, 0x0Eint 0x10cmp al, 's'jne .wait_inputmov ah, 0x00int 0x16cmp al, 0x0Djne .wait_inputmov ah, 0x0Emov al, 0x0Dint 0x10mov al, 0x0Aint 0x10mov al, 'p'int 0x10mov al, ' 'int 0x10mov al, ' 'int 0x10mov al, 'P'int 0x10mov al, 'Y'int 0x10mov al, ' 'int 0x10mov al, ' 'int 0x10mov al, '1'int 0x10mov al, '2'int 0x10mov al, 'B'int 0x10mov al, 0x0Dint 0x10mov al, 0x0Aint 0x10mov al, 'o'int 0x10mov al, 's'int 0x10mov al, ' 'int 0x10mov al, 'S'int 0x10mov al, 'Y'int 0x10mov al, 'S'int 0x10mov al, ' 'int 0x10mov al, '1'int 0x10mov al, '4'int 0x10mov al, '4'int 0x10mov al, '0'int 0x10mov al, 'K'int 0x10mov al, 'B'int 0x10jmp .print.check_input_py:mov ah, 0x0Eint 0x10mov ah, 0x00int 0x16mov ah, 0x0Eint 0x10cmp al, '\'jne .wait_inputmov ah, 0x00int 0x16mov ah, 0x0Eint 0x10cmp al, 'p'jne .wait_inputmov ah, 0x00int 0x16cmp al, 0x0Djne .wait_inputmov ah, 0x0Emov al, 0x0Dint 0x10mov al, 0x0Aint 0x10mov al, '6'int 0x10mov al, '6'int 0x10mov al, '6'int 0x10jmp .print.check_input_e:mov ah, 0x0Eint 0x10mov ah, 0x00int 0x16cmp al, 0x0Djne .wait_inputMOV AL,0x13MOV AH,0x00INT 0x10jmp .done.check_input_c1:mov ah, 0x0Eint 0x10mov ah, 0x00int 0x16cmp al, 0x0Djne .wait_input
.bad_input:mov ah, 0x0Emov al, 0x0Dint 0x10mov al, 0x0Aint 0x10mov al, 'b'int 0x10mov al, 'a'int 0x10mov al, 'd'int 0x10jmp .print
.done:retjmp .done.check_input_6.py:mov ah, 0x0Eint 0x10mov ah, 0x00int 0x16mov ah, 0x0Eint 0x10cmp al, '.'jne .wait_inputmov ah, 0x00int 0x16mov ah, 0x0Eint 0x10cmp al, 'p'jne .wait_inputmov ah, 0x00int 0x16mov ah, 0x0Eint 0x10cmp al, 'y'jne .wait_inputmov ah, 0x00int 0x16cmp al, 0x0Djne .wait_inputmov ah, 0x0Emov al, 0x0Dint 0x10mov al, 0x0Aint 0x10mov al, 'p'int 0x10mov al, 'r'int 0x10mov al, 'i'int 0x10mov al, 'n'int 0x10mov al, 't'int 0x10mov al, '('int 0x10mov al, '"'int 0x10mov al, '6'int 0x10mov al, '6'int 0x10mov al, '6'int 0x10mov al, '"'int 0x10mov al, ')'int 0x10jmp .printtimes 510-($-$$) db 0
dw 0xAA55

这里我们用的是自制操作系统专栏 里面的操作系统

双击VMwork.exe,选择os.asm

 

运行非常成功 

我们已经能解析整个引导扇区了,操作系统内核nasm代码甚至不用修改就能运行

注意,输入是输入到终端

只要

nasm os.asm -o os.img

就可以直接VMware/bochs/qemu运行os.img了 

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

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

相关文章

如何自己设计一个类似 Dubbo 的 RPC 框架?

面试题 如何自己设计一个类似 Dubbo 的 RPC 框架&#xff1f; 面试官心理分析 说实话&#xff0c;就这问题&#xff0c;其实就跟问你如何自己设计一个 MQ 一样的道理&#xff0c;就考两个&#xff1a; 你有没有对某个 rpc 框架原理有非常深入的理解。 你能不能从整体上来思考…

python 使用Whisper模型进行语音翻译

目录 一、Whisper 是什么? 二、Whisper 的基本命令行用法 三、代码实践 四、是否保留Token标记 五、翻译长度问题 六、性能分析 一、Whisper 是什么? Whisper 是由 OpenAI 开源的一个自动语音识别(Automatic Speech Recognition, ASR)系统。它的主要特点是: 多语言…

36. printf

1. printf 格式化函数说的是 printf、 sprintf 和 scanf 这样的函数&#xff0c;分为格式化输入和格式化输出两类函数。学习 C 语言的时候常常通过 printf 函数在屏幕上显示字符串&#xff0c;通过 scanf 函数从键盘获取输入。这样就有了输入和输出了&#xff0c;实现了最基本…

实验八 JSP访问数据库

实验八 JSP访问数据库 目的&#xff1a; 1、熟悉JDBC的数据库访问模式。 2、掌握使用My SQL数据库的使用 实验要求&#xff1a; 1、通过JDBC访问mysql数据&#xff0c;实现增删改查功能的实现 2、要求提交实验报告&#xff0c;将代码和实验结果页面截图放入报告中 实验过程&a…

python学opencv|读取图像(四十六)使用cv2.bitwise_or()函数实现图像按位或运算

【0】基础定义 按位与运算&#xff1a;全1取1&#xff0c;其余取0。按位或运算&#xff1a;全0取0&#xff0c;其余取1。 【1】引言 前序学习进程中&#xff0c;已经对图像按位与计算进行了详细探究&#xff0c;相关文章链接如下&#xff1a; python学opencv|读取图像&…

Flink (十二) :Table API SQL (一) 概览

Apache Flink 有两种关系型 API 来做流批统一处理&#xff1a;Table API 和 SQL。Table API 是用于 Scala 和 Java 语言的查询API&#xff0c;它可以用一种非常直观的方式来组合使用选取、过滤、join 等关系型算子。Flink SQL 是基于 Apache Calcite 来实现的标准 SQL。无论输入…

爬虫基础(六)代理简述

目录 一、什么是代理 二、基本原理 三、代理分类 一、什么是代理 爬虫一般是自动化的&#xff0c;当我们自动运行时 爬虫自动抓取数据&#xff0c;但一会就出现了错误&#xff1a; 如&#xff0c;您的访问频率过高&#xff01; 这是因为网站的反爬措施&#xff0c;如果频…

「 机器人 」利用数据驱动模型替代仿真器:加速策略训练并降低硬件依赖

前言 在强化学习(Reinforcement Learning, RL)中,策略训练需要大量的交互数据(状态、动作、奖励、下一状态),而这些数据通常来自仿真器或真实硬件。传统高保真仿真器虽然能在一定程度上模拟飞行器的动力学,但往往计算量大、开发成本高,且仍可能与真实环境存在差距。为此…

使用vhd虚拟磁盘安装两个win10系统

使用vhd虚拟磁盘安装两个win10系统 前言vhd虚拟磁盘技术简介准备工具开始动手实践1.winX选择磁盘管理2.选择“操作”--“创建VHD”3.自定义一个位置&#xff0c;输入虚拟磁盘大小4.右键初始化磁盘5.选择GPT分区表格式6.右键新建简单卷7.给卷起个名字&#xff0c;用于区分8.打开…

基于云计算、大数据与YOLO设计的火灾/火焰目标检测

摘要&#xff1a;本研究针对火灾早期预警检测需求&#xff0c;采用在Kaggle平台获取数据、采用云计算部署的方式&#xff0c;以YOLOv11构建模型&#xff0c;使用云计算服务器训练模型。经训练&#xff0c;box loss从约3.5降至1.0&#xff0c;cls loss从约4.0降至1.0&#xff0c…

计算机毕业设计Python+CNN卷积神经网络考研院校推荐系统 考研分数线预测 考研推荐系统 考研爬虫 考研大数据 Hadoop 大数据毕设 机器学习

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

为什么推荐将静态资源放在CDN上?

1. CDN 是什么&#xff1f; CDN&#xff08;Content Delivery Network&#xff09;是一种分布式网络&#xff0c;由地理上分散的服务器节点组成。其主要功能是将静态资源缓存到各地的边缘服务器上&#xff0c;从而将内容更快地传递给用户。当用户请求资源时&#xff0c;CDN 会…

Web-3.0(Solidity)ERC-20

&#x1f680; 发行自己的加密货币&#xff08;ERC-20 代币&#xff09; 你可以使用 Solidity 编写 ERC-20 智能合约 来发行自己的加密货币&#xff0c;然后部署到 以太坊&#xff08;Ethereum&#xff09; 或 BNB/Polygon 等 EVM 兼容链。 &#x1f4cc; 1. ERC-20 代币是什么…

小程序-基础加强-自定义组件

前言 这次讲自定义组件 1. 准备今天要用到的项目 2. 初步创建并使用自定义组件 这样就成功在home中引入了test组件 在json中引用了这个组件才能用这个组件 现在我们来实现全局引用组件 在app.json这样使用就可以了 3. 自定义组件的样式 发现页面里面的文本和组件里面的文…

AI 的安全性与合规性:实践中的最佳安全策略

随着人工智能&#xff08;AI&#xff09;技术的不断进步&#xff0c;越来越多的企业将其应用于实际业务场景。然而&#xff0c;AI 系统的使用也伴随着安全性和合规性方面的挑战。特别是当 AI 模型处理敏感数据时&#xff0c;如何确保数据的安全、隐私保护、以及防止滥用成为企业…

docker安装emqx

emqx安装 拉取emqx镜像 docker pull emqx/emqx:v4.1.0 运行docker容器 docker run -tid --name emqx -p 1883:1883 -p 8083:8083 -p 8081:8081 -p 8883:8883 -p 8084:8084 -p 18083:18083 emqx/emqx:v4.1.0 放行端口 1、如果要是自己的虚拟机&#xff0c;并且关闭了防火墙&a…

在K8s中部署动态nfs存储provisioner

背景 之前&#xff0c;我已经在一台worker node上安装了local lvm 的provisioner来模拟需要本地高IOPS的数据库等stafeful应用的实现。 为了后续给虚拟机里的K8s集群安装可用的metrics和logs监控系统&#xff08;metrics和logs的时序数据库需要永久存储&#xff09;&#xff0…

【OpenGL】OpenGL游戏案例(二)

文章目录 特殊效果数据结构生成逻辑更新逻辑 文本渲染类结构构造函数加载函数渲染函数 特殊效果 为提高游戏的趣味性&#xff0c;在游戏中提供了六种特殊效果。 数据结构 PowerUp 类只存储存活数据&#xff0c;实际逻辑在游戏代码中通过Type字段来区分执行 class PowerUp …

OSCP:常见文件传输方法

在渗透测试过程中&#xff0c;文件传输是一个关键环节&#xff0c;涉及不同的协议和工具&#xff0c;本文整理了 Linux 和 Windows 系统下常见的文件传输方法&#xff0c;并提供相应的命令示例。 通用文件传输方式 Base64 编码传输 Base64 可用于跨平台传输文件&#xff0c;…

【4Day创客实践入门教程】Day4 迈向高手之路——进一步学习!

Day4 迈向高手之路——进一步学习&#xff01; 目录 Day4 迈向高手之路——进一步学习&#xff01;更多的开发板外壳制作 Day0 创想启程——课程与项目预览Day1 工具箱构建——开发环境的构建Day2 探秘微控制器——单片机与MicroPython初步Day3 实战演练——桌面迷你番茄钟Day4…