Redis数据类型及底层实现

文章目录

      • 1.3.1 5种基本数据类型
        • 1.3.1.1 总结篇
        • 1.3.1.2 底层源码引入篇
          • 1.3.1.2.1 redis是字典数据库KV键值对到底是什么
          • 1.3.1.2.2 数据类型视角
          • 1.3.1.2.3 数据模型解析(重点)
          • 1.3.1.2.4 redisObjec
          • 1.3.1.2.5 SDS
        • 1.3.1.3 String
          • 1.3.1.3.1 底层分析
            • 1.3.1.3.1.1 数据结构
            • 1.3.1.3.1.2 源码分析
            • 1.3.1.3.1.3 INT 编码格式(set k1 123)
            • 1.3.1.3.1.4 EMBSTR编码格式(set k1 abc)
            • 1.3.1.3.1.5 raw 编码格式(set k1 大于44长度的一个字符串)
        • 1.3.1.4 Hash
          • 1.3.1.4.1 底层分析
            • 1.3.1.4.1.1 验证编码
            • 1.3.1.4.1.2 源码分析
            • 1.3.1.4.1.3 Ziplist
            • 1.3.1.4.1.4 hashtable
        • 1.3.1.5 List
          • 1.3.1.5.1 底层分析
            • 1.3.1.5.1.1 验证编码
            • 1.3.1.5.1.2 数据结构
            • 1.3.1.5.1.3 源码分析
        • 1.3.1.6 Set
          • 1.3.1.6.1 底层分析
            • 1.3.1.6.1.1 编码验证
            • 1.3.1.6.1.2 数据结构
        • 1.3.1.7 Zset
          • 1.3.1.7.1 底层分析
            • 1.3.1.7.1.1 编码验证
            • 1.3.1.7.1.2 数据结构(skiplist)
            • 1.3.1.7.1.3 源码分析
      • 1.3.2 3种新类型bitmap/hyperloglgo/GEO
        • 1.3.2.1 出现背景分析及统计类型
        • 1.3.2.2 Bitmap
          • 1.3.2.2.1 数据结构
          • 1.3.2.2.2 编码验证
        • 1.3.2.3 Hyperloglog
          • 1.3.2.3.1 计数算法
          • 1.3.2.3.2 HyPerLogLog如何做的?如何演化出来的?
          • 1.3.2.3.3 为什么redis集群的最大槽数是16384个?
          • 1.3.2.3.4 天猫网站首页亿级UV的Redis统计方案
        • 1.3.2.4 GEO
          • 1.3.2.4.1 案例:美团地图位置附近的酒店推送

官网命令大全: http://doc.redisfans.com/,命令不区分大小写,而key是区分大小写的,help @类型名词

1.3.1 5种基本数据类型

程序员写代码时脑子底层思维

总结:

1.3.1.1 总结篇

不同数据类型对应的底层数据结构:
1. 字符串
int:8个字节的长整型。
embstr:小于等于44个字节的字符串。
raw:大于44个字节的字符串。
Redis会根据当前值的类型和长度决定使用哪种内部编码实现。
2. 哈希(ziplist(压缩列表)+hashtable(哈希表))
ziplist(压缩列表):元素个数<512,值长度<64字节,否则,hashtable(哈希表)
ziplist内存连续紧凑,时间换空间,适合内存中数据少的情况
hashtable:读写时间复杂度为O(1)
3.列表(ziplist(压缩列表)+linkedlist(链表))
Ziplist:元素个数<512,值长度<64字节,否则,inkedlist(链表)
4. 集合(intset(整数集合)+hashtable(哈希表))
Intset:元素个数小于512,否则,hashtable
Redis会选用intset来作为集合的内部实现,从而减少内存的使用。
5. 有序集合(ziplist(压缩列表)+skiplist(跳跃表))
ziplist:元素个数<128,元素值长度<64字节,否则,skiplist

1.3.1.2 底层源码引入篇

redis源码在哪里:redis-6.0.8\redis-6.0.8\src

1.3.1.2.1 redis是字典数据库KV键值对到底是什么

redis是key-value存储系统,其中key类型一般为字符串(SDS),value类型则为redis对象(redisObject)

字典、KV是什么:每个键值对都会有一个dictEntry。类比java Map中的Entry

1.3.1.2.2 数据类型视角


上帝视角:
https://redissrc.readthedocs.io/en/latest/datastruct/dict.html
https://redissrc.readthedocs.io/en/latest/index.html

1.3.1.2.3 数据模型解析(重点)

redisObject +Redis数据类型+Redis 所有编码方式(底层实现)三者之间的关系
简单地说,redisObjec就是string、hash、list、set、zset的父类,可以在函数间传递时隐藏具体的类型信息,所以作者抽象了redisObjec结构来到达同样的目的。

1.3.1.2.4 redisObjec

Redis定义了redisObjec结构体来表示string、hash、list、set、zset等数据类型。
Redis 中每个对象都是一个redisObject结构

redisObject结构作用?
其实无论是设计redisObject,还是对存储字符设计这么多的SDS,都是为了根据存储的不同内容(type和encoding字段)选择不同的存储方式,这样可以实现尽量地节省内存空间和提升查询速度的目的。

  1. 4位的type表示具体的数据类型
  2. 4位的encoding表示该类型的物理编码方式见下表,同一种数据类型可能有不同的编码方式。(比如String就提供了3种:int embstr raw)
  3. lru字段表示当内存超限时采用LRU算法清除内存中的对象。
  4. refcount表示对象的引用计数。
  5. ptr指针指向真正的底层数据结构的指针。

编码类型:

Set age 17后redisObjec:

1.3.1.2.5 SDS


Redis中字符串的实现,SDS有多种结构(sds.h)用于存储不同的长度的字符串:
sdshdr5(2^5=32byte)、sdshdr8(2 ^ 8=256byte)、sdshdr16(2 ^ 16=65536byte=64KB)
sdshdr32(2 ^ 32byte=4GB)、sdshdr64(2的64次方byte=17179869184G)。

**len **表示SDS的长度,获取字符串长度O(1),不像C那样需要遍历一遍字符串。
**alloc **用于计算字符串已经分配的未使用的空间,作用:预分配空间的算法,而不用去考虑内存分配的问题。
buf 表示字符串数组,真存数据的。

Redis为什么重新设计一个 SDS 数据结构?
C语言没有Java里面的String类型,redis自己构建了一种名为简单动态字符串 SDS(simple dynamic string)的抽象类型,并将 SDS 作为 Redis 的默认字符串


1.3.1.3 String


1.3.1.3.1 底层分析

1.3.1.3.1.1 数据结构

详见SDS,总结如下:

1.3.1.3.1.2 源码分析

1.3.1.3.1.3 INT 编码格式(set k1 123)

当字符串键值的内容可以用一个64位有符号整形来表示时,Redis会将键值转化为long型来进行存储,此时即对应 OBJ_ENCODING_INT 编码类型。内部的内存结构表示如下:

Redis启动时会预先建立10000个分别存储09999的redisObject变量作为共享对象,这就意味着如果set字符串的键值在010000之间的话,则可以直接指向共享对象而不需要再建立新对象,此时键值不占空间!
set k1 123、set k2 123使用同一块空间

redis源代码:object.c,通过源码说明确实有10000的预分配


1.3.1.3.1.4 EMBSTR编码格式(set k1 abc)

redis源代码:object.c

对于长度小于 44的字符串,Redis 对键值采用OBJ_ENCODING_EMBSTR 方式,EMBSTR 顾名思义即:embedded string,表示嵌入式的String。从内存结构上来讲 即字符串 sds结构体与其对应的 redisObject 对象分配在同一块连续的内存空间,字符串sds嵌入在redisObject对象之中一样。


1.3.1.3.1.5 raw 编码格式(set k1 大于44长度的一个字符串)


当字符串的键值为长度大于44的超长字符串时,Redis 则会将键值的内部编码方式改为OBJ_ENCODING_RAW格式,这与OBJ_ENCODING_EMBSTR编码方式的不同之处在于,此时动态字符串sds的内存与其依赖的redisObject的内存不再连续

1.3.1.4 Hash


1.3.1.4.1 底层分析

1.3.1.4.1.1 验证编码

hash的两种编码格式:ziplist、hashtable
hash-max-ziplist-entries:使用压缩列表保存时哈希集合中的最大元素个数。
hash-max-ziplist-value:使用压缩列表保存时哈希集合中单个元素的最大长度。

采用哪种编码?
Hash类型键的字段个数小于hash-max-ziplist-entries,并且每个字段名和字段值的长度小于hash-max-ziplist-value时,Redis才会使用OBJ_ENCODING_ZIPLIST来存储该键,前述条件任意一个不满足则会转换为OBJ_ENCODING_HT的编码方式

验证:分别先将这两个值设置为3和8

验证上述选择哪种编码的几种情况:


1.3.1.4.1.2 源码分析

编码变化流程:

1.3.1.4.1.3 Ziplist

ziplist.c权威注释:

Ziplist 压缩列表是一种紧凑编码格式,时间换空间的思想,用于字段个数少,且字段值也较小的场景。压缩列表内存利用率极高的原因与其连续内存的特性是分不开的。
想想我们的学过的一种GC垃圾回收机制:标记–压缩算法,当一个hash对象只包含少量键值对且每个键值对的键和值要么就是小整数要么就是长度比较短的字符串,那么它用ziplist作为底层实现
1.3.1.4.1.3.1 压缩列表节点的构成
组成分为三部分:header+entry集合+end,其中header由zlbytes+zltail+zllen组成
zlbytes 4字节,记录整个压缩列表占用的内存字节数。
zltail 4字节,记录压缩列表表尾节点的位置。
zllen 2字节,记录压缩列表节点个数。
zlentry 列表节点,长度不定,由内容决定。
zlend 1字节,0xFF 标记压缩的结束。该字节为255(1111 1111)

压缩列表是 Redis 为节约空间而实现的一系列特殊编码的连续内存块组成的顺序型数据结构,本质上是字节数组

源代码:ziplist.c
ziplist是一个经过特殊编码的双向链表,它不存储指向上一个链表节点和指向下一个链表节点的指针,而是存储上一个节点长度和当前节点长度,通过牺牲部分读写性能,来换取高效的内存空间利用率,节约内存,是一种时间换空间的思想。只用在字段个数少,字段值小的场景里面

zlentry实体结构解析(链表中元素结构)



压缩列表的遍历:(偏移)
通过指向表尾节点的位置指针p1, 减去节点的previous_entry_length,得到前一个节点起始地址的指针。如此循环,从表尾遍历到表头节点。

ziplist存取情况:


1.3.1.4.1.3.2 明明有链表了,为什么出来一个压缩链表?

1.3.1.4.1.4 hashtable

在 Redis 中,hashtable 被称为字典(dictionary),它是一个数组+链表的结构
t_hash.c:

OBJ_ENCODING_HT 编码分析:(每个键值对都会有一个dictEntry)
OBJ_ENCODING_HT 这种编码方式内部才是真正的哈希表结构,或称为字典结构,其可以实现O(1)复杂度的读写操作,因此效率很高。在 Redis内部,从 OBJ_ENCODING_HT类型到底层真正的散列表数据结构是一层层嵌套下去的,组织关系见面图:

源代码:dict.h


1.3.1.5 List


1.3.1.5.1 底层分析

1.3.1.5.1.1 验证编码



1.3.1.5.1.2 数据结构

List的一种编码格式:list用quicklist来存储,quicklist存储了一个双向链表,每个节点都是一个ziplist

(低版本redis:ziplist+linkedList;高版本redis:quicklist+ziplist)

1.3.1.5.1.3 源码分析

quicklist.h
head和tail指向双向列表的表头和表尾

quicklistNode中的*zl指向一个ziplist,一个ziplist可以存放多个元素


1.3.1.6 Set


1.3.1.6.1 底层分析

1.3.1.6.1.1 编码验证


如果元素都是整数类型,就用intset存储,否则用hashtable(数组+链表的存来储结构)。key就是元素的值,value为null。

将配置设置为3,存储元素超过3个编码改变

验证是否改变

1.3.1.6.1.2 数据结构

t_set.c

1.3.1.7 Zset


1.3.1.7.1 底层分析

1.3.1.7.1.1 编码验证

,超过配置阈值,ziplist转化为skiplist
server.zset_max_ziplist_entries:元素个数
server.zset_max_ziplist_value:元素长度

将阈值调小:

1.3.1.7.1.2 数据结构(skiplist)

跳跃表=链表+多级索引,可以实现二分查找的有序链表,空间换时间的结构
说说链表和数组的优缺点?为什么引出跳表


(解决方法:升维,也叫空间换时间)

跳表的时间复杂度:O(logN)
二分查找,时间复杂度是O(logN)
跳表的空间复杂度:O(N)
首先原始链表长度为n
若索引是每2个结点有一个索引结点,每层索引的结点数:n/2, n/4, n/8 … , 8, 4, 2 以此类推;
若每3个结点有一个索引结点,每层索引的结点数:n/3, n/9, n/27 … , 9, 3, 1 以此类推;
所以空间复杂度是O(n);

优缺点
只有在数据量较大的情况下才能体现出来优势。而且应该是读多写少的情况下才能使用,所以它的适用范围应该还是比较有限的

维护成本相对要高 - 新增或者删除时需要把所有索引都更新一遍;
最后在新增和删除的过程中的更新,时间复杂度也是O(log n)

1.3.1.7.1.3 源码分析

t_zset.c:

1.3.2 3种新类型bitmap/hyperloglgo/GEO

1.3.2.1 出现背景分析及统计类型

出现背景:
实现问题:

  1. 手机App中的每天的⽤⼾登录信息:1天对应1系列⽤⼾ID或移动设备ID;
  2. 电商⽹站上商品的⽤⼾评论列表:1个商品对应了1系列的评论;
  3. ⽤⼾在⼿机App上的签到打卡信息:1天对应1系列⽤⼾的签到记录;
  4. 应⽤⽹站上的⽹⻚访问信息:1个⽹⻚对应1系列的访问点击。
  5. 在移动应用中,需要统计每天的新增用户数和第2天的留存用户数;
  6. 在电商网站的商品评论中,需要统计评论列表中的最新评论;
  7. 在签到打卡中,需要统计一个月内连续打卡的用户数;
  8. 在网页访问记录中,需要统计独立访客(UniqueVisitor,UV)量。

痛点:类似今日头条、抖音、淘宝这样的额用户访问级别都是亿级的,请问如何处理?
统计类型:

排序统计案例:
以抖音vcr最新的留言评价为案例,所有评论需要两个功能,按照时间排序+分页显示
能够排序+分页显示的redis数据结构是什么合适?
分析:在⾯对需要展示最新列表、排行榜等场景时,如果数据更新频繁或者需要分页显示,建议使⽤ZSet(使用Zset分析此处用户对应的评论条数不会太大)

若是使用list,存在分页数据改变问题(个人感觉能接受,不是什么么问题)


1.3.2.2 Bitmap



1.3.2.2.1 数据结构

由0和1状态表现的二进制位的bit数组,底层String实现

位图本质是数组,它是基于String数据类型的按位的操作。该数组由多个二进制位组成,每个二进制位都对应一个偏移量(我们可以称之为一个索引或者位格)。Bitmap支持的最大位数是232位,它可以极大的节约存储空间,使用512M内存就可以存储多大42.9亿的字节信息(232 = 4294967296)

案例:京东签到领取京豆(连续签到问题
在签到统计时,每个用户一天的签到用1个bit位就能表示,
一个月(假设是31天)的签到情况用31个bit位就可以,一年的签到也只需要用365个bit位,根本不用太复杂的集合类型

1.3.2.2.2 编码验证

实质是二进制的ascii编码对应,redis里用type命令看看bitmap实质是什么类型???

两个setbit命令对k1进行设置后,对应的二进制串就是0100 0001
二进制串就是0100 0001对应的10进制就是65,所以见下图:

1.3.2.3 Hyperloglog

用途:


1.3.2.3.1 计数算法

去重复统计功能的基数估计算法-就是HyperLogLog

案例:

1.3.2.3.2 HyPerLogLog如何做的?如何演化出来的?

去重复统计你先会想到哪些方式?HashSet、bitmap,优势在于精确。
HashSet存储原始数据,内存消耗大
Bitmap不存储原始数据,消耗比HashSet,随着数据集越大内存消耗也就越大
为解决内存消耗问题,采用概率算法


1.3.2.3.3 为什么redis集群的最大槽数是16384个?

https://github.com/redis/redis/issues/2576

分析:


1.3.2.3.4 天猫网站首页亿级UV的Redis统计方案


分析:
用redis的hash结构存储,按照ipv4的结构来说明,每个ipv4的地址最多是15个字节,某一天的1.5亿15个字节=2G,一个月60G,redis死定了
Hyperloglog:


为什么是12Kb?
每个桶取6位,16384
6÷8 = 12kb,每个桶有6位,最大全部都是1,值就是63

1.3.2.4 GEO

原理:
地理位置信息,地球上的地理位置是使用二维的经纬度表示,核心思想就是将球体转换为平面,区块转换为一点

难点:GeoHash核心原理解析

1.3.2.4.1 案例:美团地图位置附近的酒店推送


选型:es中地理位置信息 或 redis中geo。此处讲述geo
Redis中应该有一份静态数据(如xxx酒店位置),当我们查找会将我们实时位置上传,将附件满足的位置返回给我们(如:xxx酒店)

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

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

相关文章

uniCloud 免费版和商用版

概述 uniCloud为每个开发者提供一个免费的服务空间&#xff0c;更低门槛按量付费是serverless的特色&#xff0c;如果没有消耗硬件资源&#xff0c;就完全不用付款serverless比传统的云主机更便宜传统云主机一旦被攻击&#xff0c;高防价格非常昂贵。而uniCloud无需支付高防费…

k8s的图形化工具rancher

1、rancher&#xff1a;是一个开源的企业级多集群的k8s管理平台 2、rancher和k8s的区别 &#xff08;1&#xff09;都是为了容器的调度和编排系统 &#xff08;2&#xff09;但rancher不仅能够调度&#xff0c;还能管理k8s集群&#xff0c;自带监控&#xff08;普罗米修斯&a…

【Linux】第三十六站:信号

文章目录 一、信号的概念1.信号概念2.前台与后台进程3.信号的处理4.硬件层面5.信号与我们的代码是异步的 二、信号的产生1.产生的方式2.键盘组合键3.kill命令4.系统调用4.1 kill系统调用4.2 raise4.3 abort 5.异常软件条件5.1 异常产生信号5.2 alarm&#xff08;软件条件产生信…

【MySQL】学习如何通过DML更新数据库的数据

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-QIqURn9fNFMjLD9l {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

【Go 快速入门】数组 | 切片 | 映射 | 函数 | 结构体 | 方法和接收者

文章目录 数组切片append 函数copy 函数删除元素 映射delete 函数 函数init 特殊的函数defer 语句panic / recover 错误处理 类型结构体内存对齐JSON 序列化与反序列化方法和接收者 项目代码地址&#xff1a;03-ArraySliceMapFuncStruct 数组 基本格式&#xff1a;var 数组变…

Go 命令行解析 flag 包之快速上手

本篇文章是 Go 标准库 flag 包的快速上手篇。 概述 开发一个命令行工具&#xff0c;视复杂程度&#xff0c;一般要选择一个合适的命令行解析库&#xff0c;简单的需求用 Go 标准库 flag 就够了&#xff0c;flag 的使用非常简单。 当然&#xff0c;除了标准库 flag 外&#x…

Linux 网络流量相关工具

本文聚焦于网络流量的查看、端口占用查看。至于网络设备的管理和配置&#xff0c;因为太过复杂且不同发行版有较大差异&#xff0c;这里就不赘述&#xff0c;后面看情况再写。 需要注意的是&#xff0c;这里列出的每一个工具都有丰富的功能&#xff0c;流量/端口信息查看只是其…

使用vue_cli脚手架创建Vue项目(cmd和图形化方式)

使用vue_cli脚手架创建Vue项目&#xff08;cmd和图形化方式&#xff09; 创建项目(cmd方式) vue create vue_cli1.方向键选择manually select feature(手动选择方式创建)&#xff0c;回车 2.按空格键选择需要的组件&#xff1a;Babel、PWA、Router、Vuex、CSS&#xff0c;回…

Linux - 数据流重定向、管道符、环境变量配置文件的加载

概述 想了解Linux编程&#xff0c;shell脚本是绕不开的关键知识点&#xff0c;原计划写一个整篇来分享shell的来龙去脉&#xff0c;但知识点过于繁杂&#xff0c;先分享一下学习shell的准备工作&#xff0c;数据流重定向、管道符、环境变量配置文件的加载&#xff0c;有助于知…

Linux之安装配置CentOS 7

一、CentOS简介 CentOS&#xff08;Community Enterprise Operating System&#xff0c;中文意思是社区企业操作系统&#xff09;是Linux发行版之一&#xff0c;它是来自于Red Hat Enterprise Linux依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码&#xff0c…

YOLOv8改进 | Conv篇 | 结合Dual思想利用HetConv创新一种全新轻量化结构CSPHet(参数量下降70W)

一、本文介绍 本文给大家带来的改进机制是我结合Dual的思想利用HetConv提出一种全新的结构CSPHet,我们将其用于替换我们的C2f结构,可以将参数降低越75W,GFLOPs降低至6.6GFLOPs,同时本文结构为我独家创新,全网无第二份,非常适合用于发表论文,该结构非常灵活,利用Dual卷…

CSS探索浏览器兼容性

学习如何探索浏览器的兼容性对于编写跨浏览器兼容的CSS代码非常重要。以下是一些学习CSS兼容性的方法&#xff1a; MDN文档&#xff1a;Mozilla开发者网络&#xff08;MDN&#xff09;提供了广泛而详细的CSS文档&#xff0c;其中包含有关CSS属性、选择器和功能的信息。在MDN上…

机器学习之pandas库学习

这里写目录标题 pandas介绍pandas核心数据结构SeriesDataFrameDataFrame的创建列访问列添加列删除行访问行添加行删除数据修改 pandas介绍 pandas是基于NumPy 的一种工具&#xff0c;该工具是为了解决数据分析任务而创建的。Pandas 纳入 了大量库和一些标准的数据模型&#xff…

谷歌seo服务商如何选择?

选择谷歌SEO服务商时&#xff0c;要考虑他们的经验、专业知识、成功案例、透明度、合规性、定制能力、时间线、客户支持、沟通以及是否能够建立长期合作关系。综合评估这些因素&#xff0c;确保找到一个可信赖的合作伙伴&#xff0c;能够帮助您提升网站在谷歌搜索中的表现&…

相机与镜头

一、相机视场 相机的视场角&#xff0c;也就是相机能够看到物像角度的最大值&#xff0c;视场角与焦距的关系为像高f*tan(fov/2)。由于相机的感光面是矩形&#xff0c;所以相机能够看到的区域也是矩形。探究相机的视场角&#xff0c;便于分析物面上那些区域属于相机盲区&#x…

STM正点mini-新建工程模板,GPIO及寄存器(介绍)

一.新建工程模板(基于固件库) 1.1库函数与寄存器的区别 这里的启动文件都是根据容量来进行区分的 对MDK而言即使include了&#xff0c;也不知道在哪里找头文件 STM32F10X_HD,USE_STDPERIPH_DRIVER 二.新建工程模板(基于寄存器) 上面的大部分配置与固件库的一样 具体可以看手…

带延迟的随机逼近方案(Stochastic approximation schemes):在网络和机器学习中的应用

1. 并行队列系统中的动态定价Dynamic pricing 1.1 系统的表述 一个含有并行队列的动态定价系统&#xff0c;该系统中对于每个队列有一个入口收费(entry charge) &#xff0c;且系统运行的目标是保持队列长度接近于某个理想的配置。 这里是这个系统的几个关键假设&#xff1a;…

redis-4 搭建redis集群

1.为什么需要redis集群&#xff1f; Redis 集群提供了高可用性、横向扩展和数据分片等功能&#xff0c;使得 Redis 能够应对大规模的数据存储和高并发访问的需求。以下是一些需要使用 Redis 集群的常见情况&#xff1a; 高可用性&#xff1a;通过在多个节点之间进行数据复制和…

计算机网络——TCP协议

&#x1f4a1;TCP的可靠不在于它是否可以把数据100%传输过去&#xff0c;而是 1.发送方发去数据后&#xff0c;可以知道接收方是否收到数据&#xff1b;2.如果接收方没收到&#xff0c;可以有补救手段&#xff1b; 图1.TCP组成图 TCP的可靠性是付出代价的&#xff0c;即传输效率…

苹果提审被拒反馈崩溃日志.text | iOS 审核被拒crashLog

iOS审核人员拒绝后每个截图&#xff0c;只给了几个text文件&#xff0c;这种情况就是审核的时候运行你的代码&#xff0c;崩溃了。 仅仅看text文件&#xff0c;是看不出所以然来的&#xff0c;所以我们要将日志转换成.crash格式 1.将.text文件下载下来&#xff0c;将 .text手动…