【NJU OS】12 进程的地址空间

进程的地址空间

char *p 可以和 intptr_t 互相转换

  • 可以指向 “任何地方”
    • 合法的地址 (可读或可写)
    • 代码 (main, %rip 会从此处取出待执行的指令),只读
    • 数据 (static int x),读写
    • 堆栈 (int y),读写
    • 运行时分配的内存 (???),读写
    • 动态链接库 (???)
  • 非法的地址
    • NULL,导致 segmentation fault

外挂:攻与防

控制/数据流完整性

  • 保护进程的完整性
    • 独立的进程/驱动做完整性验证
  • 保护隐私数据不被其他进程读写
    • 拦截向本进程的 ReadProcessMemory 和 WriteProcessMemory,发现后立即拒绝执行
  • 例子
    • Denuvo Anti-Cheat, Epic Anti-Cheat Interface

其他解决方法

  • AI 监控/社会工程学:如果你强得不正常,当然要盯上你
  • 云/沙盒 (Enclave) 渲染:“计算不再信任操作系统”

总结

  • 进程的地址空间
    • 能文件关联的、带有访问权限的连续内存段
      • a.out, ld.so, libc.so, heap, stack, vdso
  • 进程地址空间的管理 API
    • mmap

【NJU OS】11 操作系统上的进程

操作系统启动后到底做了什么?

从系统启动到第一个进程

操作系统会加载 “第一个程序”

  • RTFSC (latest Linux Kernel)
    • 如果没有指定启动选项 init=,按照 “默认列表” 尝试一遍
    • 从此以后,Linux Kernel 就进入后台,成为 “中断/异常处理程序”

fork()

做一份状态机完整的复制 (内存、寄存器现场)

execve()

_exit()

结束程序执行的三种方法

exit 的几种写法 (它们是不同)

  • exit(0) - stdlib.h 中声明的 libc 函数
    • 会调用 atexit
  • _exit(0) - glibc 的 syscall wrapper
    • 执行 “exit_group” 系统调用终止整个进程 (所有线程) 细心的同学已经在 strace 中发现了
    • 不会调用 atexit
  • syscall(SYS_exit, 0)
    • 执行 “exit” 系统调用终止当前线程
    • 不会调用 atexit

总结

  • 对 “操作系统” 的完整理解
    • CPU Reset → Firmware → Loader → Kernel _start() → 执行第一个程序 /bin/init → 中断/异常处理程序
    • 一个最小的 Linux 系统的例子
  • 进程管理 API
    • fork, execve, exit: 状态机的复制、重置、销毁
    • 理论上就可以实现 “各种功能” 了!

【LeetCode】227. 基本计算器Ⅱ

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stack>
using namespace std;

class Solution {
public:
int calculate(string s) {
int ans = 0;
stack<int> st;
stack<char> opst;
int num = 0;
//遍历字符串,将数字和符号入栈,当遇到符号且符号栈顶为乘除符号时,弹出元素将计算后的重新入栈
for (int i = 0; i < s.length(); ++i) {
char c = s[i];
if (c == ' ')
continue;
if (isdigit(c)) { // 使用isdigit检查是否为数字
num = num * 10 + (c - '0');
} else {
if (!opst.empty() && (opst.top() == '*' || opst.top() == '/')) {
num = (opst.top() == '*') ? st.top() * num : st.top() / num;
opst.pop();
st.pop();
}
st.push(num);
num = 0;
opst.push(c);
}
}
// 处理遍历完字符串后,栈顶符号是乘除的情况
if (!opst.empty() && (opst.top() == '*' || opst.top() == '/')) {
num = (opst.top() == '*') ? st.top() * num : st.top() / num;
opst.pop();
st.pop();
}
st.push(num);
num = 0;
//此时符号栈中应只有加减号
while (!opst.empty()) {
char op = opst.top();
opst.pop();
int prev = st.top();
st.pop();
ans = (op == '+') ? ans + prev : ans - prev;
}
ans += st.top();
return ans;
}
};

【LeetCode】224. 基本计算器

括号展开 + 栈

核心是利用栈击穿括号,将符号转变为没有括号的样子。

栈顶保留括号前符号,加号括号内符号不变,减号括号内符号反转。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
int calculate(string s) {
stack<char> st; // 存储正负号
int ans = 0, num = 0, op = 1;
st.push(op);

for (char c : s) {
if (c == ' ') continue;
else if (c >= '0') num = num * 10 - '0' + c;
else {
ans += op * num;
num = 0;

if (c == '+') op = st.top();
else if (c == '-') op = -st.top();
else if (c == '(') st.push(op); // 将括号前符号放入栈顶
else st.pop();
}
}

return ans + op * num;
}
};

【前端】React笔记

React基础

什么是JSX?

  • JavaScripts + XML: 表示在JS代码中编写HTML模版结构,它是React中编写UI模版的方式。
  • JSX并不是标准的JS语法,它是JS的语法扩展,浏览器本身不能识别,需要通过解析工具(BABEL)做解析之后才能在浏览器中运行

在JSX中使用JS表达式

在JSX中可以通过 大括号语法{} 识别JavaScript中的表达式

  • 使用引号传递字符串
  • 使用JavaScript变量
  • 函数调用和方法调用
  • 使用JavaScript对象

React 事件绑定

  • React 基础事件绑定:on + 事件名称 = { 事件处理程序 },整体上遵循驼峰命名法
  • 使用事件对象参数:在事件回调函数中设置形参e
  • 传递自定义参数:事件绑定的位置改造成箭头函数的写法
  • 同时传递事件对象和自定义参数:在事件绑定的位置传递事件实参e和自定义参数,clickHandler中声明形参,注意顺序对应

React 组件

在React中,一个组件就是首字母大写的函数,内部存放了组件的逻辑和视图UI, 渲染组件只需要把组件当成标签书写即可

  • 状态不可变

在React中,状态被认为是只读的,我们应该始终替换它而不是修改它,直接修改状态不能引发视图更新

  • 修改对象状态

对于对象类型的状态变量,应该始终传给set方法一个全新的对象来进行修改

React 副作用管理

  • useEffect

    useEffect是一个React Hook函数,用于在React组件中创s建不是由事件引起而是由渲染本身引起的操作(副作用), 比 如发送AJAX请求,更改DOM等等

  • useEffect依赖说明

    useEffect副作用函数的执行时机存在多种情况,根据传入依赖项的不同,会有不同的执行表现

  • 没有依赖项 组件初始渲染 + 组件更新时执行

  • 空数组依赖 只在初始渲染时执行一次

  • 添加特定依赖项 组件初始渲染 + 依赖项变化时执行

React 路由

1
2
3
npm create-react-app react-router-pro # 使用CRA创建项目
npm i react-router-dom # 安装最新的ReactRouter包
npm run start # 启动项目

路由导航

声明式导航

声明式导航是指通过在模版中通过 组件描述出要跳转到哪里去,比如后台管理系统的左侧菜单通常使用这种方式进行

编程式导航

编程式导航是指通过 useNavigate 钩子得到导航方法,然后通过调用方法以命令式的形式进行路由跳转,比如想在登录请求完毕之后跳转就可以选择这种方式,更加灵活

导航传参

嵌套路由配置

什么是嵌套路由?

在一级路由中又内嵌了其他路由,这种关系就叫做嵌套路由,嵌套至一级路由内的路由又称作二级路由,例如:

嵌套路由配置

  • 使用 children属性配置路由嵌套关系
  • 使用 组件配置二级路由渲染位置

craco

  • 配置‘@’全局路径

Mock

前端在没有后端接口支持下进行接口数据模拟

插件

  • lodash
  • classnames:classnames是一个简单的JS库,可以非常方便的通过条件动态控制class类名的显示
  • day.js
  • craco
    • 配置‘@’全局路径

【技术】HTTP常用知识

HTTP常见状态码

  • 1XX:消息

    • 101 Switch Protocol:升级协议,如从 http 到 ws,此时需要反向代理支持,如 Nginx。
  • 2XX:成功

    • 200 Ok: 成功
  • 3XX:重定向

    • 301 Moved Permanently:永久重定向
    • 302 Found:临时重定向
    • 304 Not Modified:自上次请求,未修改的文件
  • 4XX:客户端错误

    • 400 Bad Request:错误的请求
    • 401 Unauthorized:未被授权,需要身份验证,例如token信息等等
    • 403 Forbidden:请求被拒绝
    • 404 Not Found:资源缺失,接口不存在,或请求的文件不存在等等
  • 5XX:服务端错误

    • 500 Internal Server Error:服务器端未知错误,一般不允许出现。
    • 502 Bad Gateway:从上游应用层未返回响应,上游应用层挂了
    • 503 Service Unavailable:服务暂时无法使用
    • 504 Gateway Timeout:网关超时,上游应用层迟迟未响应

HTTP报文

GET和POST差异

  • GET在浏览器回退时是无害的,而POST会再次提交请求。
  • GET产生的URL地址可以被Bookmark,而POST不可以。
  • GET请求会被浏览器主动cache,而POST不会,除非手动设置。
  • GET请求只能进行url编码,而POST支持多种编码方式。
  • GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
  • GET请求在URL中传送的参数是有长度限制的,而POST没有。
  • 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
  • GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
  • GET参数通过URL传递,POST放在Request body中。
  • GET产生一个TCP数据包;POST产生两个TCP数据包。

HTTP 缓存

Http 缓存分为以下两种,两者都是通过 HTTP 响应头控制缓存

  • 强制缓存

再次请求时无需再向服务器发送请求

  • 协商缓存

再次请求时,需要向服务器校验新鲜度,如果资源是新鲜的,返回 304,从浏览器获取资源

缓存策略

关于 http 缓存配置的最佳实践为以下两条:

  • 文件路径中带有 hash 值:一年的强缓存。因为该文件的内容发生变化时,会生成一个带有新的 hash 值的 URL。前端将会发起一个新的 URL 的请求。配置响应头 Cache-Control: public,max-age=31536000,immutable

  • 文件路径中不带有 hash 值:协商缓存。大部分为 public 下文件。配置响应头 Cache-Control: no-cache 与 etag/last-modified

HTTP Header

gzip 配置

一句话:gzip 的核心是 Deflate,而它使用了 LZ77 算法与 Huffman 编码来压缩文件,重复度越高的文件可压缩的空间就越大。

因此 gzip 用于 HTTP 文件传输中,比如 JS、CSS 等,但一般不会压缩图片。在 HTTP Response 报文中,用 Content-Encoding 指明使用 gzip 压缩,而以下响应头在大部分生产环境的响应报文中都可以看到。

跨域

HTTPS

HTTPS中如何保证证书是可信任的

  • 数字签名: 数字签名的原理其实很简单,就是把公钥私钥的用法反过来,之前是公钥加密、私钥解密,现在是私钥加密、公钥解密。但又因为非对称加密效率太低,所以私钥只加密原文的摘要,这样运算量就小的多,而且得到的数字签名也很小,方便保管和传输。

  • 数字证书和CA: 因为公钥是任何人都可以发布的,所以我们需要引入第三方来保证公钥的可信度,这个“第三方”就是我们常说的 CA(Certificate Authority,证书认证机构),CA 对公钥的签名认证也是有格式的,要包含公钥的序列号、用途、颁发者、有效时间等等,把这些打成一个包再签名,完整地证明公钥关联的各种信息,形成“数字证书”(Certificate)。

  • 小一点的 CA 可以让大 CA 签名认证,但链条的最后,也就是 Root CA,就只能自己证明自己了,这个就叫“自签名证书”(Self-Signed Certificate)或者“根证书”(Root Certificate)。你必须相信,否则整个证书信任链就走不下去了。

HTTP2

http2与http1.1有什么改进?

  1. 二进制分帧
  2. 请求多路复用 (Stream/Frame)
  3. 头部压缩: (HPack),其中原理是哈夫曼编码及索引表
  4. 服务端推送: (Server Push)

http2 中 Stream 与 Frame 是什么关系?

  • Stream 为 Request/Response 报文的双向通道,一个完整资源的请求与相应是一个 stream,特殊的 stream 作为 Settings、Window_Update 等 Frame 发送的通道
  • Frame 为 http2 通信的最小单位,有 Data、Headers 等,一个 Stream 包含多个 Frame,如一条 http 请求包含 Header、Data Frame 等

HTTP3

http3 基于 UDP 协议,这是与以前版本的 http 最大的不同,可以解决 http2 TCP 连接阻塞的问题。

【前端】基于Vue3的PC电商前台项目实现

前言

初学Vue的常规项目,不涉及后端接口。

项目介绍

基于Vue3和ElementPlus搭建的某服装电商前台。

技术栈

  • Vue3
  • Vue-Router
  • Vite
  • Pinia
  • ElementPlus

内容

  • 使用Vite进行项目构建,根据甲方需求,精确还原UI设计。

  • 对Axios进行简单二次封装,如请求拦截器和响应拦截器。

  • 进行路由设计,实现基于业务逻辑的组件拆分。

  • 实现购物车组件及SKU组件的封装及优化。

  • 使用Pinia进行集中状态管理,并处理用户数据路由缓存问题。

  • 实现长页面吸顶交互、图片懒加载、面包屑、放大镜、跳转第三方支付等功能,提高用户交互体验。

心得记录

用别人的组件时需注意

  • 看文档
  • 没有文档时,看props和emit

全局注册

  • 目前Vue3中vue component文件夹下的组件默认注册

解决路由缓存问题

  • 一级分类的切换正好满足上面的条件,组件实例复用,导致分类数据无法更新
  • 解决思路:1. 让组件实例不复用,强制销毁重建 2. 监听路由变化,变化之后执行数据更新操作
  • 可以给router-view添加key,也可以使用beforeRouteUpdate导航钩子。在意性能问题,选择onBeforeUpdate, 精细化控制;不在意性能问题,选择key,简单粗暴

持久化用户数据

  • Token
  • Copyrights © 2019-2024 Hxy
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信