【Linux网络】应用层自定义协议与序列化
应用层自定义协议与序列化
应用层
我们程序员写的一个个解决我们实际问题,满足我们日常需求的网络程序,都是在应用层.
协议是一种"约定".Socket的接口,在读写数据时,都是按"字符串"的方式来发送接收的.如果我们要传输一些"结构化的数据"怎么办呢?
其实,协议就是双方约定好的结构化的数据
网络版计算器
例如,我们需要实现一个服务器版的加法器.我们需要客户端把要计算的两个加数发过去, 然后由服务器进行计算,最后再把结果返回给客户端.
约定方案一:
- 客户端发送一个形如"1+1"的字符串;
- 这个字符串中有两个操作数,都是整形;
- 两个数字之间会有一个字符是运算符,运算符只能是+;
- 数字和运算符之间没有空格;
- …
约定方案二:
- 定义结构体来表示我们需要交互的信息;
- 发送数据时将这个结构体按照一个规则转换成字符串,接收到数据的时候再按照相同的规则把字符串转化回结构体;
- 这个过程叫做"序列化"和"反序列化"
序列化和反序列化
无论我们采用方案一,还是方案二,还是其他的方案,只要保证,一端发送时构造的数据,在另一端能够正确的进行解析,就是ok的.这种约定,就是应用层协议
但是,为了让我们深刻理解协议,打算自定义实现一下协议的过程。
- 我们采用方案2,我们也要体现协议定制的细节
- 我们要引入序列化和反序列化,只不过我们课堂直接采用现成的方案–jsoncpp库
- 我们要对socket进行字节流的读取处理
理解read、write、recv、send和tcp支持全双工
所以:
-
在任何一台主机上,TCP连接既有发送缓冲区,又有接受缓冲区,所以,在内核中,可以在发消息的同时,也可以收消息,即全双工
-
这就是为什么一个tcpsockfd读写都是它的原因
-
实际数据什么时候发,发多少,出错了怎么办,由TCP控制,所以TCP叫做传输控制协议
Json
Jsoncpp
Jsoncpp是一个用于处理JSON数据的C++库。它提供了将JSON数据序列化为字符串以及从字符串反序列化为C++数据结构的功能。Jsoncpp是开源的,广泛用于各种需要处理JSON数据的C++项目中。
特性
- 简单易用:Jsoncpp提供了直观的API,使得处理JSON数据变得简单。
- 高性能:Jsoncpp的性能经过优化,能够高效地处理大量JSON数据。
- 全面支持:支持JSON标准中的所有数据类型,包括对象、数组、字符串、数字、布尔值和null。
- 错误处理:在解析JSON数据时,Jsoncpp提供了详细的错误信息和位置,方便开发者调试。
当使用Jsoncpp库进行JSON的序列化和反序列化时,确实存在不同的做法和工具类可供选择。以下是对Jsoncpp中序列化和反序列化操作的详细介绍:
安装
C++
- ubuntu: sudo apt - get install libjsoncpp - dev
- Centos: sudo yum install jsoncpp - devel
序列化
序列化指的是将数据结构或对象转换为一种格式,以便在网络上传输或存储到文件中。Jsoncpp提供了多种方式进行序列化:
- 使用Json::Value的toStyledString方法
- 优点:将Json::Value对象直接转换为格式化的JSON字符串。
- 示例:
#include <iostream>
#include <jsoncpp/json/json.h>int main()
{Json::Value root;root["name"] = "joe";root["sex"] = "男";std::string s = root.toStyledString();std::cout << s << std::endl;return 0;
}
执行结果:
{"name" : "joe","sex" : "男"
}
- 使用Json::StreamWriter
- 优点:提供了更多的定制选项,如缩进、换行符等。
- 示例:
#include <iostream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>int main()
{Json::Value root;root["name"] = "joe";root["sex"] = "男";Json::StreamWriterBuilder wbuilder; // StreamWriter的工厂std::unique_ptr<Json::StreamWriter> writer(wbuilder.newStreamWriter());std::stringstream ss;writer->write(root, &ss);std::cout << ss.str() << std::endl;return 0;
}
执行结果:
{"name" : "joe","sex" : "男"
}
- 使用Json::FastWriter
- 优点:比StyledWriter更快,因为它不添加额外的空格和换行符。
- 示例:
#include <iostream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>int main()
{Json::Value root;root["name"] = "joe";root["sex"] = "男";Json::FastWriter writer;std::string s = writer.write(root);std::cout << s << std::endl;return 0;
}
执行结果:
{"name":"joe","sex":"男"}
另一种写法示例:
#include <iostream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>int main()
{Json::Value root;root["name"] = "joe";root["sex"] = "男";Json::StyledWriter writer;std::string s = writer.write(root);std::cout << s << std::endl;return 0;
}
执行结果:
{"name" : "joe","sex" : "男"
}
反序列化
反序列化指的是将序列化后的数据重新转换为原来的数据结构或对象。Jsoncpp提供了以下方法进行反序列化:
- 使用Json::Reader
- 优点:提供详细的错误信息和位置,方便调试。
- 示例:
#include <iostream>
#include <jsoncpp/json/json.h>int main() {std::string json_string = "{\"name\":\"张三\",\"age\":30,\"city\":\"北京\"}";// 解析JSON字符串Json::Value root;Json::Reader reader;bool parsingSuccessful = reader.parse(json_string, root);if (!parsingSuccessful) {// 解析失败,输出错误信息std::cout << "Failed to parse JSON: " << reader.getFormattedErrorMessages() << std::endl;return 1;}// 访问JSON数据std::string name = root["name"].asString();int age = root["age"].asInt();std::string city = root["city"].asString();// 输出结果std::cout << "Name: " << name << std::endl;std::cout << "Age: " << age << std::endl;std::cout << "City: " << city << std::endl;return 0;
}
执行结果:
Name: 张三
Age: 30
City: 北京
- 使用Json::CharReader的派生类(不推荐,上面的足够了)
在某些情况下,你可能需要更精细地控制解析过程,可以直接使用Json::CharReader的派生类。
但通常情况下,使用Json::parseFromString或Json::Reader的parse方法就足够了。
总结
你可以用toStyledString、StreamWriter和FastWriter提供了不同的序列化选项,它们提供强大的错误处理机制。
Json::Reader和parseFromString函数是Jsoncpp中主要的反序列化工具,在进行序列化和反序列化时,请确保处理所有可能的错误情况,并验证输入和输出的有效性。
Json::Value
Json::Value是Jsoncpp库中的一个重要类,用于表示和操作JSON数据结构。以下是一些常用的Json::Value操作列表:
- 构造函数
- Json::Value():默认构造函数,创建一个空的Json::Value对象。
- Json::Value(Json::ValueType type, bool aValue = false):根据给定的类型创建一个Json::Value对象。
- 访问元素
- Json::Value& operator[](const char key)*:通过键(字符串)访问对象中的元素。如果键不存在,则创建一个新的元素。
- Json::Value& operator[](const std::string& key):同上,但使用std::string类型的键。
- Json::Value& operator[](ArrayIndex index):通过索引访问数组中的元素。如果索引超出范围,则创建一个新的元素。
- Json::Value at(const char key)*:通过键访问对象中的元素,如果键不存在则抛出异常。
- Json::Value at(const std::string& key):同上,但使用std::string类型的键。
- 类型检查
- bool isNull():检查值是否为null类型。
- bool isBool():检查值是否为布尔类型。
- bool isInt():检查值是否为32位整数类型。
- bool isInt64():检查值是否为64位整数类型。
- bool isUInt():检查值是否为无符号整数类型。
- bool isUInt64():检查值是否为64位无符号整数类型。
- bool isIntegral():检查值是否为整数或可转换为整数的浮点数。
- bool isDouble():检查值是否为双精度浮点数。
- bool isNumeric():检查值是否为数字(整数或浮点数)。
- bool isString():检查值是否为字符串。
- bool isArray():检查值是否为数组。
- bool isObject():检查值是否为对象(即键值对的集合)。
- 赋值和类型转换
- Json::Value& operator=(bool value):将布尔值赋给Json::Value对象。
- Json::Value& operator=(int value):将32位整数赋给Json::Value对象。
- Json::Value& operator=(int64_t value):将64位整数赋给Json::Value对象。
- Json::Value& operator=(uint value):将无符号整数赋给Json::Value对象。
- Json::Value& operator=(uint64_t value):将64位无符号整数赋给Json::Value对象。
- Json::Value& operator=(double value):将双精度浮点数赋给Json::Value对象。
- Json::Value& operator=(const char value)*:将C字符串赋给Json::Value对象。
- Json::Value& operator=(const std::string& value):将std::string赋给Json::Value对象。
- bool asBool():将值转换为布尔类型(如果可能)。
- int asInt():将值转换为32位整数类型(如果可能)。
- Int64 asInt64():将值转换为64位整数类型(如果可能)。
- UInt64 asUInt64():将值转换为64位无符号整数类型(如果可能)。
- std::string asString():将值转换为字符串类型(如果可能)。
- 数组和对象操作
- size_t size():返回数组或对象中的元素数量。
- bool empty():检查数组或对象是否为空。
- void resize(ArrayIndex newSize):调整数组的大小。
- void clear():删除数组或对象中的所有元素。
- void append(const Json::Value& value):在数组末尾添加一个新元素。
- Json::Value& operator[](const char key, const Json::Value& defaultValue = Json::nullValue)*:在对象中插入或访问一个元素,如果键不存在则使用默认值。
- Json::Value& operator[](const std::string& key, const Json::Value& defaultValue = Json::nullValue):在对象中插入或访问一个元素,如果键不存在则使用默认值,但使用std::string类型的键。
相关文章:
【Linux网络】应用层自定义协议与序列化
应用层自定义协议与序列化 应用层 我们程序员写的一个个解决我们实际问题,满足我们日常需求的网络程序,都是在应用层. 协议是一种"约定".Socket的接口,在读写数据时,都是按"字符串"的方式来发送接收的.如果我们要传输一些"结构化的数据"怎么办…...
Excel提取单元格特定符号左右两边内容
公式: RIGHT(字符串, 字符个数) :从字符串右边开始,提取指定字数内容 公式应用: RIGHT(A1, LEN(A1) - SEARCH(“-”, A1))—提取单元格A1中符号“-”右边的字符串 LEN(A1) - SEARCH(“-”, A1) 即是返回符号“-”右边的字符串长…...
集群/微服务/分布式
目录 介绍 集群 微服务 优点 缺点 如何管理和监控微服务架构中的多个微服务? 服务治理 配置管理 监控与告警 容器化与编排 安全管理 分布式 三者关系 分布式和集群的区别是什么? 概念 工作方式 节点角色 应用场景 故障处理 微服务 微…...
安装docker
安装docker 一、关闭防火墙和SELinux 1.1systemctl stop firewalld 1.2setenfoce 0 二、配置内核转发以及网桥过滤 2.1vi /etc/sysctl.d/k8s.conf 2.2sysctl -p /etc/sysctl.d/k8s.conf :让文件生效 2.3modprobe br_netfilter:加载模块 若未生效成功…...
热力图是什么?三分钟学会热力图数据分析怎么做!
目录 一、热力图是什么? (一)基本概念 (二)常见类型 (三)优点 二、热力图分析工具 (一)FineBI (二)Tableau (三)P…...
Spring、SpringMVC、SpringBoot、SpringCloud 联系与区别
Spring、SpringMVC、SpringBoot、SpringCloud 联系与区别 一、引言 在 Java 企业级开发中,Spring 家族框架是绕不开的核心技术栈。从基础架构到 Web 开发,再到微服务架构,Spring 系列框架通过层层抽象,逐步简化开发复杂度。本文…...
操作系统导论——第26章 并发:介绍
本章介绍为单个运行进程提供的新抽象:线程(thread)。经典观点是一个程序只有一个执行点(一个程序计数器,用来存放要执行的指令),但多线程(multi-threaded)程序会有多个执…...
如何使用测试软件 Jmeter
第一步,点击 编辑 添加线程组 第二步,右键单击线程组,添加取样器 HTTP 请求 第三步,设置请求路径 第四步,添加 查看结果树 用于查看请求响应 最后点击绿色小三角启动即可...
HarmonyOS NEXT 免费无广告看电影app:从想法到实现的经验总结
学习一项新技能,最好也是最快的方法就是动手实战。学习鸿蒙也一样,给自己定一个小目标,直接找项目练,这样进步是最快的。最近,我在网上看到360周董的一句话:“想干什么就去干,干得烂总比不干强!…...
《算法导论(第4版)》阅读笔记:p14-p16
《算法导论(第4版)》学习第 9 天,p14-p16 总结,总计 3 页。 一、技术总结 无。 二、英语总结(生词:2) 1. in light of (1)释义 idiom. in light of 是美式用法,英式用法是 in the light of。take sth into consideration(鉴…...
kuka, fanuc, abb机器人和移动相机的标定
基础知识 : 一, 9点标定之固定相机标定: 图1: 固定位置相机拍照 因为相机和机器人的基坐标系是固定的, 所以在海康威视相机的9点标定功能栏中, 填上海康使用“圆查找”捕捉到的坐标值, 再将机器人显示的工具坐标系在基坐标系的实时位置pos_act值填入物理坐标X, Y中即可 图2:…...
【MyBatis-6】MyBatis动态SQL:灵活构建高效数据库查询的艺术
在现代企业级应用开发中,与数据库的交互是不可或缺的核心部分。MyBatis作为一款优秀的持久层框架,因其简洁、灵活和高效而广受开发者喜爱。其中,动态SQL功能更是MyBatis的一大亮点,它允许开发者根据不同条件灵活构建SQL语句&#…...
从零开始理解FlashAttention:算法细节图解
🧠 向所有学习者致敬! “学习不是装满一桶水,而是点燃一把火。” —— 叶芝 我的博客主页: https://lizheng.blog.csdn.net 🌐 欢迎点击加入AI人工智能社区! 🚀 让我们一起努力,共创…...
js原型污染 + xss劫持base -- no-code b01lersctf 2025
题目信息:Found this new web framework the other day—you don’t need to write any code, just JSON. 我们先来搞清楚究竟发生了什么 当我们访问 /index /*** 处理 /:page 路径的 GET 请求* param {Object} req - 请求对象* param {Object} reply - 响应对象* returns {Pro…...
面试题:Java集合框架高频面试题总结
# Java集合框架高频面试题总结 ## 集合框架概述 1. **Java集合框架的主要组成部分** - Collection接口 - List: 有序可重复 - Set: 无序不可重复 - Queue: 队列 - Map接口: 键值对存储 2. **集合框架的继承体系** - Collection - List → Arra…...
【大模型ChatGPT+ArcGIS】数据处理、空间分析、可视化及多案例综合应用
在数字化和智能化的浪潮中,GIS(地理信息系统)和GPT(生成式预训练模型)的结合正日益成为推动科研、城市规划、环境监测等领域发展的关键技术。GIS以其强大的空间数据处理、先进的空间分析工具、灵活的地图制作与可视化能…...
使用JMETER中的JSON提取器实现接口关联
一、JSON提取器介绍 JSON提取器是JMETER工具中用于从JSON响应中提取数据的重要组件,常常用于接口关联场景中(参数传递)。 二、添加JSON提取器 举例(积分支付接口请求数据依赖于创建订单接口响应的payOrderId) 1.在…...
Filecoin存储管理:如何停止Lotus向特定存储路径写入新扇区数据
Filecoin存储管理:如何停止Lotus向特定存储路径写入新扇区数据 引言背景问题场景解决方案步骤1:修改sectorstore.json文件步骤2:重新加载存储配置步骤3:验证更改 技术原理替代方案最佳实践结论 引言 在Filecoin挖矿过程中&#x…...
Elasticsearch太重?它的超轻量的替代品找到了!
简要介绍 在海量数据时代,快速而精准地找到所需信息至关重要。如果您正为此苦恼,或者您是 Elasticsearch 的用户,并对其资源消耗或性能有所关注,那么今天我要向您介绍一款名为 Manticore Search 的开源搜索数据库,它或…...
【计算机视觉】OpenCV实战项目: Fire-Smoke-Dataset:基于OpenCV的早期火灾检测项目深度解析
Fire-Smoke-Dataset:基于OpenCV的早期火灾检测项目深度解析 在当今数字化时代,火灾检测技术的智能化发展至关重要。传统的火灾检测方法依赖于烟雾传感器或人工监控,往往存在响应延迟或误报的问题。而随着计算机视觉技术的飞速发展࿰…...
STM32--PWM--函数
TIM_OCInitTypeDef TIM_OCInitTypeDef 是 STM32 标准外设库中用于配置定时器输出比较(Output Compare, OC)功能的结构体,主要用于 PWM 生成、单脉冲输出等场景。 typedef struct {uint16_t TIM_OCMode; // 输出比较模式uint16_t TIM_…...
软件测试应用技术(3) -- 软件评测师(十六)
5 事件驱动架构软件测试 5.1 事件驱动架构软件测试概述 事件驱动架构,简称EDA,是常用的架构范式中的一种,其关注事件的产生、识别、处理、响应。对于事件驱动架构系统的测试应特别注意其业务逻辑处理上的异步特性导致的缺陷和事件队列处理中…...
人工智能之数学基础:二次型
本文重点 二次型作为线性代数领域的重要概念,架起了代数方程与几何分析之间的桥梁。从古典解析几何中的圆锥曲线方程到现代优化理论中的目标函数,二次型以其简洁的数学表达和丰富的结构特性,在数学物理、工程技术和经济金融等领域发挥着不可替代的作用。 二次型的基本概念…...
MongoDB 创建索引原则
MongoDB索引创建原则 MongoDB索引是提高查询性能的关键工具,以下是创建索引的核心原则和最佳实践: 一、索引基础原则 1. 索引本质:索引类似书籍目录,通过B-Tree数据结构对字段值排序存储,使查询复杂度从O(n)降为…...
空间复杂度** 与 **所需辅助空间**
当我们说一个算法的 空间复杂度是 O(1),通常特指“辅助空间”是 O(1),即:除了输入数据本身之外,算法只使用常数级别的额外空间。 ✅ 正确认解: O(1) 空间复杂度 ≈ O(1) 辅助空间 这表示: 不随输入规模增长…...
Spring Web MVC快速入门
什么是Spring Web MVC Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从⼀开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来⾃其源模块的名称(Spring-webmvc),但它通常被称为"Spring MVC". View(视图) 指在应⽤程序…...
RT-Thread 深入系列 Part 1:RT-Thread 全景总览
摘要: 本文将从 RTOS 演进、RT-Thread 的版本分支、内核架构、核心特性、社区与生态、以及典型产品应用等多维度,全面呈现 RT-Thread 的全景图。 关键词:RT-Thread、RTOS、微内核、组件化、软件包管理、SMP 1. RTOS 演进与 RT-Thread 定位 2…...
黄金、碳排放期货市场API接口文档
StockTV 提供了多种期货市场的数据接口,包括获取K线图表数据、查询特定期货的实时行情等。以下为对接期货市场的详细接口说明。 一、获取K线图表数据 通过调用/futures/kline接口,您可以获取指定期货合约的历史K线数据(例如开盘价、最高价、…...
SpringAI框架中的RAG知识库检索与增强生成模型详解
SpringAI框架中的RAG知识库检索与增强生成模型详解 一、RAG简介 RAG(Retrieval-Augmented Generation)可以通过检索知识库,克服大模型训练完成后参数冻结的局限性,携带知识让大模型根据知识进行回答。 二、SpringAI框架支持的R…...
LVGL- 按钮矩阵控件
1 按钮矩阵控件 lv_btnmatrix 是 LVGL(Light and Versatile Graphics Library) v8 中提供的一个非常实用的控件,用于创建带有多个按钮的矩阵布局。它常用于实现虚拟键盘、数字键盘、操作面板、选择菜单等场景,特别适用于嵌入式设…...
C++学习-入门到精通-【5】类模板array和vector、异常捕获
C学习-入门到精通-【5】类模板array和vector、异常捕获 类模板array和vector、异常捕获 C学习-入门到精通-【5】类模板array和vector、异常捕获一、array对象array对象的声明使用array对象的例子使用常量变量指定array对象的大小 二、基于范围的for语句三、利用array对象存放成…...
`待办事项css样式
vue <template> <div class"box"> <div class"head"> <h2>待办事项</h2> <input type"text" placeholder"请输入您的待办事项,按回车添加"> </div> <div class"main&q…...
spring ai alibaba 使用 SystemPromptTemplate 很方便的集成 系统提示词
系统提示词可以是.st 文件了,便于修改和维护 1提示词内容: 你是一个有用的AI助手。 你是一个帮助人们查找信息的人工智能助手。 您的名字是{name} 你应该用你的名字和{voice}的风格回复用户的请求。 每一次回答的时候都要增加一个65字以内的标题形如:【…...
Vue3 官方宣布淘汰 Axios,拥抱Alova.js
过去十年,Axios 凭借其简洁的API设计和浏览器/Node.js双环境支持,成为前端开发者的首选请求库。但随着现代前端框架的演进和工程化需求的升级,Alova.js 以更轻量、更智能、更符合现代开发范式的姿态登场。 一、Axios的痛点 1,冗余的适配逻辑,比如Axios的通用配置(但实际…...
2025年数维杯C题数据收集方式分享
2025年数维杯C题”清明时节雨纷纷,何处踏青不误春?“需要我们根据题目的要求自行数据,下图为目前已经收集到的问题一二数据集,本文将为大家详细的介绍具体收集数据方式以及处理方式。 通过网盘分享的文件:分享数据集 …...
手写 vue 源码 === ref 实现
目录 响应式的基本实现 Proxy 与属性访问器 Proxy 的工作原理 属性访问器(Getter/Setter) 为什么解构会丢失响应性 ref 和 toRefs 的解决方案 proxyRefs:自动解包 ref 总结 Vue3 的响应式系统是其核心特性之一,它通过 Pro…...
Python爬虫抓取Bilibili弹幕并生成词云
1. 引言 Bilibili(B站)是国内知名的视频分享平台,拥有海量的弹幕数据。弹幕是B站的核心特色之一,用户通过弹幕进行实时互动,这些数据对于分析视频热度、用户情感倾向等具有重要价值。 本文将介绍如何利用Python爬虫技…...
【Python 字典(Dictionary)】
Python 中的字典(Dictionary)是最强大的键值对(key-value)数据结构,用于高效存储和访问数据。以下是字典的核心知识点: 一、基础特性 键值对存储:通过唯一键(Key)快速访…...
k8s之探针
探针介绍: 编排工具运行时,虽说pod挂掉会在控制器的调度下会重启,出现pod重启的时候,但是pod状态是running,无法真实的反应当时pod健康状态,我们可以通过Kubernetes的探针监控到pod的实时状态。 Kubernetes三种探针类…...
upload-labs靶场通关详解:第三关
一、分析源代码 代码注释如下: <?php // 初始化上传状态和消息变量 $is_upload false; $msg null;// 检查是否通过POST方式提交了表单 if (isset($_POST[submit])) {// 检查上传目录是否存在if (file_exists(UPLOAD_PATH)) {// 定义禁止上传的文件扩展名列表…...
LeetCode:101、对称二叉树
递归法: /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {…...
zst-2001 历年真题 UML
UML - 第1题 ad UML - 第2题 依赖是暂时使用对象,关联是长期连接 依赖:依夜情 关联:天长地久 组合:组一辈子乐队 聚合:好聚好散 bd UML - 第3题 adc UML - 第4题 bad UML - 第5题 d UML - 第6题 …...
对称加密以及非对称加密
对称加密和非对称加密是两种不同的加密方式,它们在加密原理、密钥管理、安全性和性能等方面存在区别,以下是具体分析: 加密原理 对称加密:通信双方使用同一把密钥进行加密和解密。就像两个人共用一把钥匙,用这把钥匙锁…...
Java反射 八股版
目录 一、核心概念阐释 1. Class类 2. Constructor类 3. Method类 4. Field类 二、典型应用场景 1. 框架开发 2. 单元测试 3. JSON序列化/反序列化 三、性能考量 四、安全与访问控制 1. 安全管理器限制 2. 打破封装性 3. 安全风险 五、版本兼容性问题 六、最佳…...
C++跨平台开发实践:深入解析与常见问题处理指南
一、跨平台开发基础架构设计 1.1 跨平台架构的核心原则 分层设计模式: 平台抽象层(PAL):将平台相关代码集中管理 核心逻辑层:完全平台无关的业务代码 平台实现层:针对不同平台的特定实现 代码组织最佳实践: pro…...
【“星睿O6”AI PC开发套件评测】+ MTCNN 开源模型部署和测试对比
经过了前几篇文章的铺垫,从搭建 tensorflow 开发环境,到测试官方 onnx 模型部署到 NPU,接着部署自己的 mnist tensorflow 模型到 NPU。这是一个从易到难的过程,本篇文章介绍开源复杂的人脸识别模型 mtcnn 到 “星睿O6” NPU 的部署…...
JAVA实战开源项目:装饰工程管理系统 (Vue+SpringBoot) 附源码x
本文项目编号 T 179 ,文末自助获取源码 \color{red}{T179,文末自助获取源码} T179,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...
centos 7 安装 java 运行环境
centos 7 安装 java 运行环境 java -version java version "1.8.0_131" Java(TM) SE Runtime Environment (build 1.8.0_131-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)java -version java version "1.8.0_144" Java(TM) …...
力扣题解:21.合并两个有序链表(C语言)
将两个升序链表合并为一个新的升序链表是一个经典的链表操作问题。可以通过递归或迭代的方法来解决。以下是解释和代码实现: 递归: 每次比较两个链表的头节点,将较小的节点添加到新链表中,并递归处理剩余部分。 截至条件…...
iOS App 安全性探索:源码保护、混淆方案与逆向防护日常
iOS App 安全性探索:源码保护、混淆方案与逆向防护日常 在 iOS 开发者的日常工作中,我们总是关注功能的完整性、性能的优化和UI的细节,但常常忽视了另一个越来越重要的问题:发布后的应用安全。 尤其是对于中小团队或独立开发者&…...