抖音客户端一面

C++ | 字节抖音客户端一面

Http握手过程

1. 客户端问候(Client Hello)

客户端向服务器发送一个“问候”消息,其中包含客户端支持的SSL/TLS版本、加密算法、压缩方法以及一个随机数。

  • version 版本号,https也有版本号哦TLS 1.0、TLS 1.1、TLS 1.2等等

  • random 随机数,用来以后计算对称加密key

    最后加密数据用的主密钥,需要客户端和服务端一起协商出来。后面服务端的 Server Hello 阶段也会生成一个随机数。一同用来计算出主密钥。

  • Session ID 保存会话的标识

    这个 Session ID 是可以重用的,具体看服务端资源和支持情况。如果要复用 Session ID, SSL 服务端需要维护连接的状态和上次握手成功留下的加密信息。如果是第一次访问该网址,会话 ID 尚未创建,客户端没记录,为 0。如果客户端保存了 Session ID 的信息,下次发起 SSL 请求的时候会带上。

  • Cipher Suites 说明客户端支持的加密方式,如上说明支持16种加密方式。

    客户端可以支持的密码套件列表。这些套件会根据优先级排序。每一个套件代表一个密钥规格。以 “TLS” 开头,接着是密钥交换算法,然后用 “WITH” 连接加密算法和认证算法。一个加密套件有这么几个内容:密钥交换算法、加密算法(会带有支持的最高密钥位数)、认证算法还有加密方式。最终使用什么密码套件是服务端决定的。要什么密码套件会在 Server Hello 中进行反馈。

  • 压缩算法

    这里为 0,说明不支持压缩算法

在这里插入图片描述

2. 服务器问候(Server Hello)

服务器响应客户端的“问候”消息,选择一个双方都支持的SSL/TLS版本、加密算法和压缩方法,并生成一个随机数,同时将其发送给客户端。

  • random 随机数

    和客户端的随机数两个随机数将参与主密钥(master key)的创建。

  • 压缩方法

    这里为 0,表示不使用压缩算法

在这里插入图片描述

3. 服务器证书(Server Certificate)

服务器将自己的数字证书发送给客户端。这个证书由受信任的第三方(如CA机构)签发,包含服务器的公钥和服务器身份信息。客户端使用内置的根证书列表来验证服务器证书的合法性和有效性。

  • 版本

    对应的就是 X.509 V3 标准

  • 序列号

    serialNumber,证书颁发者唯一序列号。

  • 签名算法ID

    这里指的是使用 SHA-256 进行摘要,RSA 进行加密的签名算法。

  • 证书颁发者

    issuer,就是颁发该证书的 CA 的信息。里面携带后该 CA 的唯一名称(DN,Distinguished Name),比如国家为 US(美国),组织机构为 DigiCert Inc.,名称为 GeoTrust CN RSA CA G1。后面我们需要从证书链找到该 CA 证书(具体方法:在其他证书的subject字段查找国家、组织机构、名称),去认证当前证书

  • 有效期

    validity,证书的起始时间和终止时间

  • 对象公钥信息

    subjectPublicKeyInfo。因为这是服务端证书,这个公钥后面将用于主密钥的交换过程,从中可以了解到这个公钥采用 RSA 加密

然后是证书颁发机构的签名信息:

  • 签名算法

    algorithmIdentifier,这里得出使用的还是 SHA-256 摘要加 RSA 加密的签名算法。这个就是认证该证书的 CA 证书使用的签名算法。

  • 签名信息

    encrypted,这个信息的内容,CA 证书对 SHA-256 对上面的数据部分进行摘要后,使用 RSA 的私钥加密获得。后面会用在该证书的认证过程,取出 CA 证书的公钥,解密签名信息,用同样的算法获取数据摘要,对比一下是否相同。

4. 服务器密钥交换(Server Key Exchange)

密钥交换阶段,这个步骤是可选步骤,对 Certificate 阶段的补充,只有在这几个场景存在:

  • 协商采用了 RSA 加密,但是服务端证书没有提供 RSA 公钥。

  • 协商采用了 DH(EC Diffie-Hellman) 加密,但是服务端证书没有提供 DH 参数。

  • 协商采用 fortezza_kea 加密,但是服务端证书没有提供参数。

5. 服务器完成(Server Hello Done)

服务器表示问候阶段已经完成,等待客户端的响应。

6. 客户端密钥交换(Client Key Exchange)

这里,客户端不直接生成加密密钥,而是通过之前客户端和服务端生成的随机数又再生成一个随机数,使用前面协商好的用 EC Diffie-Hellman 算法进行加密传输给服务端。这个值又被称为 “premaster secret“。

服务端收到这个报文后,会使用自己的私钥解开这个随机数。在这个阶段过后,服务端和客户端都有三个随机数:客户端随机数、服务端随机数和预备主密钥。在服务端收到了 Client Key Exchange 消息后,两端都按照相应的算法生成了主密钥,加密密钥交换完成。交换完了,因为主密钥是两个端按照约定好的算法产生的,如何保证这个主密钥是正确的?这时候会进入下一个阶段。客户端和服务端会对握手信息使用 SHA 做个摘要,用 AES 加密算法和主密钥加密,传递给对方验证。

7. 客户端完成(Client Finished)

客户端通知服务端,后续的报文将会被加密

8. 服务器完成(Server Finished)

服务器也发送一条加密消息,表示它已经完成了密钥交换和会话密钥的生成。

9. 加密通信开始

此时,客户端和服务器都已经生成了相同的会话密钥,接下来的通信将使用会话密钥进行对称加密,以确保数据传输的保密性和完整性。

Https能否防住DNS攻击

DNS攻击是指针对DNS系统的各种攻击手段,包括但不限于:

  • DNS缓存污染(DNS Cache Poisoning):攻击者向DNS缓存服务器注入虚假的DNS记录,使用户访问错误的IP地址。
  • DNS劫持(DNS Hijacking):攻击者通过篡改DNS解析过程,将用户引导到恶意网站。
  • 中间人攻击(Man-in-the-Middle Attack):攻击者在客户端和DNS服务器之间拦截并篡改DNS请求和响应。
HTTPS的保护范围

HTTPS通过加密传输数据,确保数据在客户端和服务器之间传输时不会被窃听或篡改。具体来说,它可以保护以下内容:

  • 数据加密:防止数据在传输过程中被窃听。
  • 数据完整性:防止数据在传输过程中被篡改。
  • 身份验证:通过数字证书验证服务器的身份,确保客户端连接到的是合法服务器。

虽然HTTPS能保护数据传输的安全,但在DNS解析过程中,HTTPS并不能直接防止DNS攻击。因为在建立HTTPS连接之前,客户端需要通过DNS解析来获取服务器的IP地址,如果DNS解析过程被攻击者篡改,用户可能会连接到错误的服务器。

什么是拥塞控制

主机A                                                 主机C------路由器A------> 路由器B------路由器C---------> 
主机B                                                 主机D前提条件:有限的链路缓存
链路容量是 R当分组的到达路由器C被丢弃的时候,那么上游路由器A-C之间的路由器的传输容量都被浪费掉了。

如果网络发生拥塞,将会导致我们会重传不需要重传的分组,导致恶性循环,或者由于丢失导致上游路由器带宽的浪费,所有拥塞控制的目的就是:

最大限度的利用带宽,传输有效的数据。

拥塞控制算法需要解决以下三个问题

TCP如何限制数据的发送速率(拥塞窗口机制cwnd);
TCP如何检测网络中是否拥塞(轻微拥塞,拥塞);
TCP采用什么算法来调整速率(什么时候调整,调整多少,轻微拥塞如何调整,拥塞如何调整)。
拥塞控制检测的方法
端到端的拥塞控制:在这种拥塞控制方法中,由发送端自己来判断是否拥塞,然后调整传输速率;对于TCP发送方来说,没有一个精确的方法知晓路由器的中间状态,没有一个明确的信号告知拥塞已经发生,典型的TCP推断是否拥塞,通常看是否有丢包的情况发生。为什么会丢包?中间路由器缓存溢出导致丢包。段所在的分组,分组所在的帧出现bit反转,出错导致校验未通过丢包。针对以上两种情况需要澄清一个问题就是,无线网以前出错导致的丢包远远小于溢出导致的丢包,可以忽略不记。    

拥塞控制的主要方法

拥塞控制机制通常分为端到端控制和网络辅助控制两大类。

端到端控制方法
  1. TCP 拥塞控制
    • 慢启动(Slow Start):发送方开始时发送数据的速率较低,然后逐步增加发送速率,直到检测到网络拥塞。
    • 拥塞避免(Congestion Avoidance):在检测到拥塞信号(如数据包丢失或延迟增加)后,发送方会降低发送速率,然后再缓慢增加,避免再次发生拥塞。
    • 快速重传(Fast Retransmit)和快速恢复(Fast Recovery):在检测到数据包丢失时,发送方会立即重传丢失的数据包,并进入快速恢复阶段,在此阶段会减少发送速率以防止拥塞恶化。
  2. 流量控制:确保发送方不会向接收方发送超过其处理能力的数据量。流量控制通常通过滑动窗口协议来实现。
网络辅助控制方法
  1. 主动队列管理(Active Queue Management, AQM)
    • RED(Random Early Detection):在队列达到某个阈值时,随机丢弃部分数据包,以提醒发送方减缓发送速率。
    • ECN(Explicit Congestion Notification):通过在数据包头部标记拥塞通知,让发送方知道网络中存在拥塞,从而调整发送速率。
  2. 流量整形(Traffic Shaping):控制数据发送的时间和速率,使得数据流平稳,避免突发流量导致拥塞。

死锁的条件

1. 互斥条件(Mutual Exclusion)

资源在某个时刻只能被一个进程占用。如果某个资源已经被一个进程占用了,其他进程必须等待,直到该资源被释放。这意味着资源不能被多个进程共享。

2. 请求和保持条件(Hold and Wait)

一个进程已经持有至少一个资源,同时又请求新的资源,而新的资源已经被其他进程占有,此时该进程会被阻塞,但它对自己已持有的资源保持不放。

3. 不可剥夺条件(No Preemption)

资源不能被强行从一个进程中夺走,只有该进程自己才能在完成任务后自愿释放所占有的资源。

4. 环路等待条件(Circular Wait)

在系统中存在一个进程集合{P1,P2,…,Pn},其中P1等待P2占有的资源,P2等待P3占有的资源,……,Pn等待P1占有的资源,从而形成一个环状的等待关系。

static变量存储在哪里

在这里插入图片描述

static变量存储在全局数据区(Data Segment),具体来说,它们位于以下两种区域之一:

  1. 静态/全局数据区(Data Segment):这是程序的数据段,专门存储初始化的全局变量和静态变量。这部分内存由操作系统在程序加载时分配,并在程序运行期间一直存在。
  2. BSS段(Block Started by Symbol Segment):这部分内存用于存储未初始化的全局变量和静态变量。虽然这部分变量在编译过程中没有显式初始化,但在程序开始执行时会被操作系统初始化为0。

进程和线程的区别

本质区别:

进程是资源分配的基本单位,线程是CPU调度的基本单位

  1. 定义和结构
    • 进程:进程是程序的一个实例,它在其自己的地址空间中运行。每个进程至少包含一个线程(主线程),并拥有自己的虚拟内存、系统资源和独立的执行环境。进程之间互相隔离,一个进程的崩溃通常不会影响到其他进程。
    • 线程:线程是进程中的执行单元。一个进程可以包含多个线程,它们共享父进程的地址空间和资源,如内存和文件句柄等。线程主要用于实现任务的并行执行。
  2. 资源共享
    • 进程:进程之间不共享内存或资源,除非通过进程间通信(IPC)机制显式共享,如套接字、信号量、共享内存等。
    • 线程:同一进程内的线程共享内存和资源,这使得线程间的数据交换和通信更为容易和快速,但也需要注意同步和互斥问题,以避免竞态条件和死锁。
  3. 开销和性能
    • 进程:创建和管理进程的开销相对较大,因为每个进程需要独立的地址空间和系统资源。进程切换涉及更多的时间和资源,如保存和加载不同进程的上下文。
    • 线程:线程的创建和切换开销较小,因为它们共享相同的环境和资源。线程间的切换只需要较少的资源重新配置。
  4. 通信方式
    • 进程:进程间通信需要特定的机制,如管道、消息队列、共享内存等,这些机制通常涉及更复杂的设置和管理。
    • 线程:由于线程共享同一内存空间,它们可以直接通过读写同一内存区域来进行通信,但这要求程序正确地处理同步问题,以防数据不一致。

继承是否会破坏封装

个人理解。一般而言,继承是不会破坏封装的。继承的本意是为了增强代码的复用性和组织性。只要使用正常的访问控制修饰符public, privateprotected就不会破坏封装。

了解的设计模式

LRU算法:设定Cache大小 + 过期时间

见LeetCode 146。相比于原题多了设定过期时间,逻辑是一样的,只需要掌握对应语言的设定时间戳的API,即可。此题在大厂秋招的话难度还可能继续进阶,比如实现线程安全。此时需要加锁,但是直接对哈希表加锁的话粒度太大,所以需要分桶。然后继续加难度,如何实现高并发,此时需要异步,对应到C++就是std::async,可以直接调用API或者手写(太花时间且难度有点高了)。

#include <iostream>
#include <unordered_map>
#include <chrono>
#include <thread>class Node {
public:int key, val;std::chrono::time_point<std::chrono::steady_clock> timestamp;Node *prev = nullptr, *next = nullptr;Node (int k = 0, int v = 0): key(k), val(v), timestamp(std::chrono::steady_clock::now()){ }
};class LRUCache {
public:LRUCache(int capacity, int ttl): capacity(capacity), ttl(ttl) {dummy = new Node();dummy->prev = dummy;dummy->next = dummy;}int get(int key) {auto node = getNode(key);if (node == nullptr) {return -1;}return node->val;}void put(int key, int value) {auto node = getNode(key);if (node != nullptr) {node->val = value;node->timestamp = std::chrono::steady_clock::now();return;}node = new Node(key, value);keyToNode[key] = node;pushToFront(node);if (keyToNode.size() > this->capacity) {auto last = dummy->prev;keyToNode.erase(last->key);remove(last);delete last;}return;}private:int capacity;std::chrono::seconds ttl;std::unordered_map<int, Node*> keyToNode;Node *dummy;void remove(Node *x) {if (x != nullptr) {x->prev->next = x->next;x->next->prev = x->prev;}}void pushToFront(Node *x) {if (x != nullptr) {x->prev = dummy;x->next = dummy->next;x->prev->next = x;x->next->prev = x;}}Node* getNode(int key) {auto it = keyToNode.find(key);if (it == keyToNode.end()) {return nullptr;}auto node = it->second;if (std::chrono::steady_clock::now() - node->timestamp > ttl) {remove(node);keyToNode.erase(it);delete node;return nullptr;}node->timestamp = std::chrono::steady_clock::now();remove(node);pushToFront(node);return node;}
};int main() {using namespace std;LRUCache* cache = new LRUCache(2, 5); cout << "Test Case 1:" << endl;cache->put(1, 1);cache->put(2, 2);cout << "Get 1: " << cache->get(1) << " (Expected: 1)" << endl; cache->put(3, 3);cout << "Get 2: " << cache->get(2) << " (Expected: -1)" << endl; cache->put(4, 4);cout << "Get 1: " << cache->get(1) << " (Expected: -1)" << endl; cout << "Get 3: " << cache->get(3) << " (Expected: 3)" << endl; cout << "Get 4: " << cache->get(4) << " (Expected: 4)" << endl; cout << "Test Case 2:" << endl;cache->put(5, 5);cout << "Get 3: " << cache->get(3) << " (Expected: -1)" << endl; cout << "Get 4: " << cache->get(4) << " (Expected: 4)" << endl; cout << "Get 5: " << cache->get(5) << " (Expected: 5)" << endl; std::this_thread::sleep_for(std::chrono::seconds(6)); cout << "Get 4 after TTL expiration: " << cache->get(4) << " (Expected: -1)" << endl; delete cache;return 0;
}

最后给大家推荐一个LinuxC/C++高级架构系统教程的学习资源与课程,可以帮助你有方向、更细致地学习C/C++后端开发,具体内容请见 https://xxetb.xetslk.com/s/1o04uB

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

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

相关文章

使用API有效率地管理Dynadot域名,设置待删除域名抢注请求

简介 Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮箱&…

爬虫学习2:爬虫爬取网页的信息与图片的方法

爬虫爬取网页的信息与图片的方法 爬取人物信息 import requestshead {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0" } # 这是get请求带参数的模式…

了解Linux中的shell脚本

目录 1、什么是shell 2、编写第一个shell文件 3、shell的权限 4、变量 5、 shell传递参数 6、shell数组 7、shell基本运算符 7.1 算术运算符 7.2 关系运算符 7.3 布尔运算符 7.4 逻辑运算符 7.5 字符串运算符 8、控制语句 8.1 if 8.2 for 8.3 while语句 9、其他 1、…

C#初级——条件判断语句和循环语句

条件判断语句 简单的条件判断语句&#xff0c;if()里面进行条件判断&#xff0c;如果条件判断正确就执行语句块1&#xff0c;如果不符合就执行语句块2。 if (条件判断) { 语句块1 } else { 语句块2 } int age 18;if (age < 18){Console.WriteLine("未…

Anaconda安装-超详细版(2023)

Anaconda安装 - 超详细版&#xff08;2023&#xff09; 前言&#xff1a;彻底卸载pythonAnaconda下载地址安装详细步骤配置环境变量检验安装是否成功更改conda源&#xff08;后续安装第三方库可以加快速度&#xff09;超详细彻底卸载Anaconda教程Tensorflow-gpu 安装 前言&…

ORBSLAM3 ORB_SLAM3 Ubuntu20.04 ROS Noetic 虚拟机镜像 下载

下图是build.sh 和 build_ros.sh编译结果截图&#xff1a; slam数据集测试视频&#xff1a; orbslam3 ubuntu20.04 test 下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1nre0Y9vig5QXIGU52qCLbQ?pwd9rbi 提取码&#xff1a;9rbi

【系列教程之】1、点亮一个LED灯

1、点亮一个LED灯 作者将狼才鲸创建日期2024-07-23 CSDN教程目录地址&#xff1a;【目录】8051汇编与C语言系列教程本Gitee仓库原始地址&#xff1a;才鲸嵌入式/8051_c51_单片机从汇编到C_从Boot到应用实践教程 本源码包含C语言和汇编工程&#xff0c;能直接在电脑中通过Keil…

【iOS】内存五大分区

目录 堆&#xff08;Heap&#xff09;是什么五大分区栈区堆区全局/静态区常量区&#xff08;即.rodata&#xff09;代码区&#xff08;.text&#xff09; 函数栈堆和栈的区别和联系图解 OC语言是C语言的超集&#xff0c;所以先了解C语言的内存模型的内存管理会有很大帮助。C语言…

常识判断1

1.法律 &#xff08;1&#xff09;行政法 &#xff08;2&#xff09;刑法 3.新公务员法 &#xff08;4&#xff09;宪法 &#xff08;5&#xff09;民法 &#xff08;6&#xff09;监察法 &#xff08;7&#xff09;婚姻法 &#xff08;8&#xff09;反不正当竞争法

二次元手游《交错战线》游戏拆解

交错战线游戏拆解案 游戏亮点即核心趣味 一、关键词&#xff1a; 回合制游戏、二次元、机甲、横板、剧情、养成、异星探索。 二、游戏亮点&#xff1a; 符合目标群体审美的原画。 三、核心趣味&#xff1a; 抽卡、肝或者氪金解锁新皮肤。 核心玩法及系统规则 核心玩法&…

英特尔终于宣布了解决CPU崩溃和不稳定性问题的方法,声称过高的电压是根本原因;补丁预计将于8月中旬推出【更新】

英特尔终于宣布了解决CPU崩溃和不稳定性问题的方法&#xff0c;声称过高的电压是根本原因&#xff1b;补丁预计将于8月中旬推出【更新】 英特尔官方宣布&#xff0c;已找到困扰其CPU的崩溃问题的根本原因&#xff0c;并将于8月中旬前发布微码更新以解决这一问题&#xff0c;从而…

Godot游戏制作 02玩家1.0版

Unity大神&#xff0c;YouTube百万游戏开发者的启蒙老师&#xff0c;Brackeys&#xff0c;携 Godot 新手教程&#xff0c;正式回归。 转自&#xff1a;https://youtu.be/LOhfqjmasi0?si4RguI6-pXHZ2mk9K 资产&#xff1a;https://brackeysgames.itch.io/brackeys-platformer-b…

SpringBoot3整合Druid报错Cannot load driver class: org.h2.Driver

报错显示springboot自带的H2数据库报错&#xff0c;其实是因为druid并未加载进去。如果你其它配置都没问题的话&#xff0c;请检查druid的依赖是什么版本的&#xff0c;因为springboot3刚开始是不支持druid的。 方案一&#xff1a; 即需要手动在resources目录下创建META-INF/s…

java算法day20

java算法day20 701.二叉搜索树中的插入操作450.删除二叉搜索树中的节点108 将有序数组转换为二叉搜索树 本次的题目都是用递归函数的返回值来完成&#xff0c;多熟悉这样的用法&#xff0c;很方便。 其实我感觉&#xff0c;涉及构造二叉树的题目&#xff0c;用递归函数的返回值…

优秀的Linux Shell终端Starship Shell的安装和配置

文章目录 简介安装startship1.安装 starship 二进制文件:2.将初始化脚本添加到您的 shell 的配置文件3、配置4、日志安装字体nerd-fonts编写脚本安装字体Nerd字体全量安装文档简介 Starship是一款轻量、迅速、可无限定制的高颜值终端! Starship Shell是一个用Rust编写的开源…

visio 打开、插入、转换以及保存 DWG 和 DXF (AutoCAD) 绘图

打开、插入、转换以及保存 DWG 和 DXF (AutoCAD) 绘图 Visio 计划 2 Visio Professional 2021 Visio Standard 2021 Visio Professional 2019 更多... 如果要在 Visio 绘图中使用AutoCAD对象&#xff0c;可以使用 Visio 打开它们并将其转换为 Visio 形状。 还可以将 Visio 绘…

图灵测试:人工智能与人类沟通的界限

图灵测试是评估人工智能&#xff08;AI&#xff09;是否能够表现出与人类相似的智能的重要标准之一。它由英国数学家兼计算机科学家艾伦图灵在1950年提出&#xff0c;其核心目的是测试一个机器是否能够表现出类似于人类思维的能力&#xff0c;从而模拟人类的智能。这一测试也因…

汇编语言例题分析

以下数据段定义了如下数据&#xff0c;对应内存图请填空&#xff0c;写出每个内存字节中的2位16进制数&#xff08;注意写准确&#xff0c;2位16进制数&#xff0c;末尾不带h&#xff09;。 Data1 segment x db 1,2,3 y db “ABa” z dw 1,2 Data1 ends 物理地址从0000开始&…

PostgreSQL异常:An I/O error occurred while sending to the backend

在使用PostgreSQL数据库批量写入数据的时候&#xff0c;遇到了一个问题&#xff0c;异常内容如下&#xff1a; Cause: org.postgresql.util.PSQLException: An I/O error occurred while sending to the backend.报错内容 报错提示1 Caused by: org.postgresql.util.PSQLExc…

[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-25 ADC模块FEP-DAQ9248采集显示波形方案

软件版本&#xff1a;Anlogic -TD5.9.1-DR1_ES1.1 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用安路(Anlogic)FPGA 实验平台&#xff1a;米联客-MLK-L1-CZ06-DR1M90G开发板 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 ht…