-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent.json
1 lines (1 loc) · 53.5 KB
/
content.json
1
[{"title":"网络","date":"2020-05-18T07:07:32.157Z","path":"2020/05/18/网络/","text":"现代因特网概述多层结构TCP/IP协议簇的五层模型分层的理由协议分层 将复杂的任务拆解成几个较小的、简单的任务。 让开发人员可以仅关注其中的一层进行开发 方便替换、修改原有的实现 降低层与层之间的依赖 每一层的东西一定是实现逻辑关联的任务,可以帮助复用逻辑 有利于标准化 分层的原则 双向通信:如果支持双向通信,每一层应当能实现相反的任务,比方说发出请求和接受响应 对等体:协议每一层的输入输出在两端应当是同样格式的对象 逻辑连接:在双向通信和对称性两个原则支持下,可以认为同一层之间具有一个逻辑连接 TCP/IP协议簇的分层模型 image-20200421100938195 image-20200421101003395 对比OSI七层模型一般来说认为TCP/IP的五层模型中的应用层包含了OSI中的应用层、表示层、会话层。 image-20200421104314055 各层描述应用层通信两端:进程(程序)到进程(程序) 逻辑单元:消息 常见的包括HTTP、HTTPS、DNS、DHCP。DHCP协议:一个局域网的网络协议,帮助分配IP给局域网用户和对它们进行统一管理。 传输层逻辑单元:段/用户数据报 传输层负责向应用层提供服务:从运行在应用层的程序得到消息,并把它投递到目的主机相应的应用程序。 主要包括TCP、UDP和SCTP(面向多媒体) 网络层网络层负责在源计算机和目的计算机之间创建一个连接。 通信两端:主机到主机。 逻辑单元:数据报 IP:IP是一个无连接的协议,不提供流量控制、拥塞控制和差错控制服务。 ARP地址解析协议:(通常在DHCP协议之后)帮助IP寻找一台主机或一台路由器的链路层地址(MAC)。地址解析就是主机在发送帧之前将目标IP地址转换成目标MAC地址的过程。(IPv6中使用NDP代替ARP) 数据链路层逻辑单元:帧 路由器负责选择链路进行传输,而数据链路层负责链路间的传输。链路可以是具有链路层交换机的局域网或是广域网。 物理层逻辑单元:比特 image-20200421103851191 封装与解封装向下封装,向上解封装,保证对等体。 多路复用和多路分解当然,一次仅能封装一个,因此,仍需要指定上层用了什么协议。 image-20200421104105337 IP地址解析 A,B,C类地址: 0 ~ 127(0与127段不适用),128~191,192 ~ 223 网络号+ 子网号 + 主机号 :10.0.17.0/24,采用等长子网划分,子网掩码为255.255.255.248,该网络的最大子网个数为2^5 =32、每个子网内的最大分配地址个数2^3 -2 = 6 (主机号全0表示本地,全1表示广播,不算有效地址), 应用层(主要讨论HTTP)URL 统一资源定位符作为文件,网页需要有唯一的标识与其他的网页区分开来。 四个标识符: 协议类型标识 主机:这里通常指域名或对应的IP地址 端口号 路径:具体的网页文件相对路径 HTTP报文结构 image-20200421113010045 HTTP报文结构与对应信息 基本结构如上图(请求行/响应行、首部行、空行、主体) 请求方法解释(表示这个HTTP请求动作的行为和目的) get:向服务器请求文档 head:类似get,但是只请求页面的首部信息,用于 post:从客户端向服务器发送一些信息 delete:删除网页 响应状态码含义 10x:临时响应,请求已被接受,需要继续处理。 20x:成功。 30x:重定向。 40x:客户端错误。 50x:服务器错误。 首部行:每一个首部行都意味着额外的信息 HTTP版本演变 HTTP各个版本 HTTP连接最显著的特点就是客户端每次发送请求都需要服务器进行回应,在请求结束之后,会主动释放连接。(一次连接) HTTP1.0:默认短连接。意味着每次客户端与服务器交互,都需要建立一个连接,处理完之后就释放连接。即使是同一对客户与服务器,客户端每次请求都要建立一个单独的连接,处理完请求之后就释放连接。1.0中通过在首部加Connection:keep-alive来开启心跳机制维持长连接。 HTTP1.1:默认支持并使用持久连接(解决了HTTP1.0的连接无法复用的问题),提供了将请求管线化的功能(虽然Pipeline一直没有投入使用) 请求的管线化:客户端可以一次性发送多个HTTP请求,提供与身份认证、状态管理相关的请求头和响应头来帮助确定一个请求属于哪个连接。但是接收还是严格地串行返回请求,要按服务器响应的顺序来接收,不允许交错到达,一旦前面的请求阻塞,后面的响应就无法到达了,这种情况叫做队首阻塞,也因此,管线化Pipelining技术并没有在实际中大规模使用,一般浏览器都是大部分关闭的。 使用连接池来管理持久连接。 建立连接, 结束时不关闭而是放进池中,3. 需要同目的的连接时,把它取出来, 定时清理连接。 2.0之前持久连接的两个性能问题: 串行的文件传输:传输的request和response都是基本于文本的,这样,所有的数据必须按顺序传输,比如需要传输:hello world,只能从h到d一个一个的传输,不能并行传输,因为接收端并不知道这些字符的顺序,所以对单个HTTP报文进行 并行传输在HTTP1.1是不能实现的。 连接数过多难以管理,也不支持这么高的并发 HTTP2.0: 核心机制:全新的二进制分帧层和流:没有改变http1.1的语义,而是加了一层封装,把HTTP1.1的首部信息封装到HEADER Frame(首部帧)中,而对应的消息正文(Request Body)则封装到数据帧Data Frame中。 通过序号对每个帧进行顺序标识,这样即使在乱序传输之后也可以被成功组合,于是就支持了并行传输。 支持多路复用 同域名下所有通信都在单个连接上完成,同个域名只需要占用一个 TCP 连接,使用一个连接并行发送多个请求和响应。 单个连接可以承载任意数量的双向数据流,单个连接上可以并行交错的请求和响应,之间互不干扰。 数据流优先级:帧们拥有1-256之间的权重,也可以和其他帧有显式的依赖关系。但是这并不是强制的,这是为了防止又会发生类似队首阻塞的情形。 核心特性: 多路复用/连接共享:允许单一的HTTP2通过单线程并行地连接发起多个请求或响应(在HTTP1.x的版本要发起多个并行请求以提升性能必须要多个TCP连接)。全新的二进制分帧层,能够将 HTTP 消息分解为独立的帧(首部帧和数据帧),允许交错发送,然后在另一端根据帧的stream ID重新组装。 解决了管线化的队首阻塞的问题。大大降低了延迟,提高了网络利用率 数据流:http消息按头部和主体封装成头部帧和数据帧,在数据流中传输,在另一端组合 服务器推送Server push(cache push):能够以push的方式(也就是客户端没有主动请求)把客户端需要的内容预先发送过去。 头部压缩:用编码器配合一个头部域编码表来压缩。(旧的http仅压缩主体部分,用gzip之类或者转为二进制) 旧版本中不再适用于HTTP2的优化: JS文件的合并:过去优化的一个主要方向就是尽量的减少HTTP的请求数, 对我们工程中的代码,研发时分模块开发,上线时我们会把所有的代码进行压缩合并,合并成一个文件,这样不管多少模块,都请求一个文件,减少了HTTP的请求数。但是这样做有一个非常严重的问题:文件的缓存。当我们有100个模块时,有一个模块改了东西,按照之前的方式,整个文件浏览器都需要重新下载,不能被缓存。现在我们有了HTTP/2了,模块就可以单独的压缩上线,而不影响其他没有修改的模块。 多域名提高浏览器的下载速度:之前有一个优化就是把css文件和js文件放到2个域名下面,这样浏览器就可以对这两个类型的文件进行同时下载,避免了浏览器6个通道的限制,这样做的缺点也是明显的,1.DNS的解析时间会变长。2.增加了服务器的压力。有了HTTP/2之后,根据上面讲的原理,就不用这么搞了,成本会更低。 HTTPS 区别:HTTPS在建立完TCP连接之后,就开始TLS的混合加密,就是说,先用非对称加密生成对称密钥,再用对称密钥进行数据安全传输。 http80无状态,明文传输;https443 如何解决http不安全的问题? 窃听:混合加密防止窃听 篡改:消息摘要算法防止篡改 冒充:公钥放到CA数字证书中防止冒充 防止窃听,混合加密: 对称加密、非对称加密与散列算法 对称:双方都使用同一个密钥。这样一旦密钥被获取一切秘密就不存在了。 AES、DES、RC4 非对称:每个人拥有 私钥-公钥 对, 使用公钥加密过的信息,仅有对应私钥可以解密。因此,使用对方的公钥加密,然后发送给对方即可。缺陷是速度慢。1. RSA、DH、ECC 防止篡改,验证完整性:散列算法:通常用于校验完整性1. MD5、SHA CA证书, 为什么要有CA证书?:防止公钥被中间人劫持,中间人用自己的公钥给发送方。 TLS(SSL)是怎么实现加密的?(一,客户端向服务器索要CA证书;二,双方协商一个session key,这个过程是非对称加密的;三,双方采用会话密钥进行通信)1. 建立TCP连接。 2. 服务端发送CA证书(公钥)给客户端 3. 客户端可以通过CA root证书判断服务端证书的真伪。 4. **服务端证书获取**:服务器B将公钥P发送给CA认证机构,CA计算一个HASH值附在末尾,然后加密,客户端只要用CA公钥解密之后,就可以用相同的HASH算法计算一下HASH是否相等,来确认公钥的可靠性。 5. DH算法协商会话密钥session key,就是说得到一个对称密钥。 6. 稍具体一些就是,服务期和客户都用自己的私钥加密公钥,接着两边交换私钥,各自再用新得到的私钥加密;最终得到一个对称密钥。 7. 利用对称密钥对传输数据进行加密。 Cookies与SessionCookie 用户与服务器的交互:赋予了 无状态的HTTP服务器状态,常用于识别用户并记录用户信息: Cookies使用例子: Susan首次使用amazon amazon后端产生cookie并存储,然后在响应中通过Set-cookie告知Susan的浏览器 Susan的浏览器接收响应报文并在对应amazon域名的cookie文件中添加一行。 这样amazon服务器就能跟踪识别Susan(的账户)了。 Session? 从访问某网址到浏览器显示的过程 浏览器敲入一个域名,尽可能详情的说下接下来网络协议层面发生了什么 DNS-UDP… 浏览器将url中抽取出域名字段,传给本地的DNS客户端 (DNS概括):hosts -> 本地DNS解析器缓存 -> “”本地”DNS服务器(配置的首选DNS服务器) -> 确认是否转发模式 -> 向上逐级查询或是从13台DNS根服务器开始查询 (具体)查DNS,先找hosts,再找本地DNS解析器的缓存,再找本机的TCP|IP协议簇配置的首选DNS服务器,又叫做本地DNS服务器,就是接着,如果是转发模式,就去查上一级服务器,查不到就逐级查;如果不是转发模式,那就从13台DNS根服务器开始解析。 最终收到应答报文,含有主机对应的IP地址 4. 浏览器收到来自DNS的IP地址,就可以向HTTPS服务器发起TCP连接 ARP:地址解析协议, 用于实现从 IP 地址到 MAC 地址的映射,即询问目标IP对应的MAC地址。 MAC:48位物理地址,由数据链层的以太网设备唯一决定,不可变。 1. 以太帧用MAC地址标识目的地址和源地址。 OSI多层结构 TODO 每层独立完成自己的工作,不依赖其他层。层与层之间通过标准接口来传输数据,这样简单易用且方便扩展。 二层基于MAC地址转发数据帧,三层基于IP地址转发报文 SOCKET TODO socket 的诞生是为了应用程序能够更方便的将数据经由传输层来传输。它连接应用层和传输层,作为一个文件描述符让应用去读写而连接到网络。UNIX的哲学是一切都是文件,就如同一个运行的程序被pid文件标识,一个进程占用了一个端口并建立起对应协议的通信,那么socket就标识这个通信资源,它必须包括两边的IP地址和端口,以及连接使用的协议这五种信息。通常socket编程分为 2 个部分,服务端需要建立 socket 来监听指定的地址,然后等待客户端来连接。而客户端则需要建立 socket 并与服务端的 socket 地址进行连接。(被打开的文件在进程中被fd标识)。 Socket():创建一个socket。 Bind():绑定地址,即该socket负责哪个资源。 Listen():开始监听。 Connect():建立连接,此时发生三次握手。 Accept():接收请求。内核为监听套接字维护两个队列,已完成连接队列和未完成连接队列。Accept会返回和已完成连接队列的队头的IP地址、端口对应的Socket。已完成队列的大小取决于backlog和系统参数somaxconn的较小值。 Recv()/Send():数据发送和接收 讲一下连接步骤(服务器监听、客户端请求、连接确认) 服务器监听:一个套接字绑定一个应用程序,实时监控网络状态,等待客户端的连接请求。 客户端请求:客户端向服务器提出连接请求。当然,客户端必须首先能够描述服务端的套接字,也就是要指明地址和端口号。 连接确认:服务端监听到客户的连接请求后,就响应这个请求,创建一个新socket与客户端建立连接并通信。 讲一下通信流程 Cookies,Session和Token TODO 概念 异同 交换 电路交换:必须拨号建立一条连接,也就是一条专用的物理通道,这里的专用是指这条通道只允许连接上的两台用户使用。 优劣:实现简单,但容易导致通路短缺,不适用于大型网络, 报文交换:报文是通信链路中一次要发送的数据,报文交换就是把整个报文完整的发送到链路中,在某个节点存储下来之后再发送到下一个节点。 优劣:不需要连接。但是由于需要在节点存储转法,因此时间延迟会比较大 分组交换:分组交换采用转发存储技术,将一个完整的报文,分成若干个分组,再进行转发,而且每个分组之间经过哪一个节点,与上一个分组完全没有关系,这一点在某些网络节点发生网络阻塞时会显得尤其重要。 优劣:发送数据灵活,时间延迟较低;但是发送和接收的设备会比较复杂。 设备 网关:可以连接不同网络协议的网络 路由器:连接相同网络协议的网络。它通过收到包的IP地址,查找路由表来决定转发到哪个端口。 交换机:传统交换机只处理以太网报文,完全不看IP层的内容。每次主机发送以太网帧,源地址填写自己的MAC地址,目的地址填写对端的MAC地址或者广播地址。交换机每次收到以太网帧,就在MAC地址表中记录这个帧的源MAC地址和收到这个帧的端口,这叫做MAC地址学习,然后再看这个帧的目的MAC地址,如果在MAC地址表中找到,就发给对应的端口,否则广播。 大端:TCP协议簇规定:把接收到的第一个字节当作高位字节看待,因此发送端发送的第一个字节是高位字节;而在发送端发送数据时,发送的第一个字节是该数值在内存中的起始地址处对应的那个字节,也就是说,该数值在内存中的起始地址处对应的那个字节就是要发送的第一个高位字节(即:高位字节存放在低地址处);由此可见,多字节数值在发送之前,在内存中因该是以大端法存放的;所以说,网络字节序是大端字节序。 x86小端,TCP大端。 这大小端是说,32位机器,即CPU寄存器宽度32,数据的存储是以字节为单位,但是寄存器宽度却大于字节,因此一个long类型的数据该以怎样的顺序存储就成了学问。大端派将一个序列中的高位字节放在低位地址,符合人类阅读顺序。 平常说多少位的机器,是说CPU中“算术逻辑单元(ALU)”的宽度(也就是对应的AC累加寄存器(暂存ALU的运算结果)的位数),他代表的是CPU一次能并行处理的数据位数。 浏览器渲染: 浏览器自上而下逐行解析 HTML 内容,经过词法分析、语法分析,构建 DOM 树。当遇到外部 CSS 链接时,主线程调用网络请求模块异步获取资源,不阻塞而继续构建 DOM 树,获取到CSS之后构建CSSOM树。遇到外部JS链接时,由于JS可能会修改DOM和CSSOM造成回流和重绘,所以会令DOM树的构建阻塞,不过主进程仍旧会使用轻量级的扫描器去发现后续需要下载的外部资源并提前发起请求。JS下载完毕之后调用V8引擎解析、编译并执行。构建完DOM树之后,渲染就好了。 页面生命周期:页面从发起请求开始,结束于跳转、刷新或关闭。衡量一个页面性能的方式有很多,但能给用户带来直接感受的是页面何时渲染完成、何时可交互、何时加载完成。其中,有两个非常重要的生命周期事件,DOMContentLoaded 事件表示 DOM 树构建完毕,可以安全地访问 DOM 树所有 Node 节点、绑定事件等等;load 事件表示所有资源都加载完毕,图片、背景、内容都已经完成渲染,页面处于可交互状态。 传输层(TCP/UDP)TCPTCP协议主要特性TCP是面向连接的(点对点),提供可靠交付,面向字节流(把应用层交付的数据)、全双工、有流量控制和拥塞控制的数据传输协议。 面向连接的:需要维护连接才能传输数据,点对点的连接也意味着不支持广播。 提供可靠交付:指的是,它对差错控制、流量控制、拥塞控制的支持。 TCP报文信息解构 image-20200518150358351 序列号ISN:ISN由计时器结合Hash算法生成。在保留位SYN置为1的时候,它标识当前的报文段以及按字节帮助标识当前传输的数据,这一标识可以用于确认传输数据包的顺序,令接收方可以按照发送方的顺序来重组数据,以保证数据的完整性。 相对序列号表示发送端已成功发送的数据的字节数。比方说,此次序列号为500,发送数据量为100,那么下一次序列号就是600. 相对ACK表示发送端已经成功接收的数据的字节数,或者说,直到序列号为ACK-1为止的数据包都被成功接收到了;并且表示期望收到序号等同于为ACK的数据包。 确认号ACK:上方已解释 标准允许轻微的延时确认,延时不会超过两个数据包。 首部长度:指明了TCP头部中共有多少个4字节长的字。(TCP长度为20-50字节, 保留位: SYN/FIN仅用于连接和断开连接,不包含有效数据。 窗口大小RWND:建立连接时描述接收窗口的初始大小,建立连接后描述当前的接收窗口大小。 校验和:TCP校验和覆盖TCP首部和主体,通过循环加法之后取反,得到校验和 紧急指针: 选项部分: MSS最大报文段长度,单个TCP包所包含的最大字节数。(实际通信的时候采用的是两边最大报文段长度的较小值) 窗口扩大选项:在建立连接中的SYN和SYN/ACK包中定义,在建立连接后才起效。最多偏移7位。 … TCP握手与挥手 TCP连接与断开连接 请讲一下三次握手?为什么是三次不是两次,为什么是三次不是四次?连接时的各种状态意味着什么? 三次握手是指TCP连接中客户端和服务端建立连接的过程。第一,客户端向服务端发送一个报文段,其中保留位synchronous置为1,表示请求同步和连接,这个报文它会根据计时器和哈希算法计算得到一个ISN初始化序号,能够标识这个报文段;第二,服务端收到了这个同步报文段,在验算了16位的校验和之后,它会发送一个确认报文段,这个报文段的保留位的ACK和SYN都置为1,表示这既是一个用于告知对方自己成功收到数据的报文段,也是一个请求连接报文段,其中ACK由ISN+1得到,表示这之前的数据都收到了,同时还附带了服务段的ISN初始化序号;第三,客户端校验这个报文,回复一个ACK报文段。 之所以是三次不是二次,是因为二次了话,可能会发生一个,客户端的初次请求超时的一个情况,那么假设两次握手,服务器端会觉得连接成功,就会向客户端发送数据,导致额外的、无用的开销和错误。之所以不是四次,是因为理论上建立连接过程中超时、堵塞总是有可能的,不管几次都没办法百分百确认连接,那么一般来讲,三次就已经足够了。 第一次发送,C:SYN-SENT;第二次发送,S:SYN-RCVD,C:ESTABLISHED;第三次发送,S:ESTABLISHED 对应的四次挥手,请讲一下 (https://draveness.me/whys-the-design-tcp-time-wait 状态转移图,极好) 四次挥手是指TCP中客户端和服务端关闭先前建立的连接的过程。第一,客户端向服务端发送连接释放报文段,就是说这个报文段的保留位FIN置为1,此时客户端进入FIN_WAIT1状态,停止发送数据;第二,服务端接收报文,发送确认报文。此时服务端进入CLOSE_WAIT状态,而客户端接收到对应之后进入FIN_WAIT2状态。第三,服务端把其他要发送的数据发送完之后,就向客户端发送连接释放报文。此时服务器就进入最后确认LAST_ACK状态,等待客户端的确认,客户端收到这个消息则会进入一个TIME_WAIT状态,表示客户端没有数据要发送了,但仍然保留接收对方数据的能力;第四,客户端收到连接释放报文以后,发送确认,客户端进入时间等待状态,等待客户端经过2倍的最长报文段寿命之后,才能撤销TCB传输控制模块,进入CLOSED状态。而服务端一旦收到了这一确认报文段,就可以直接进入CLOSED状态。因此服务端结束连接通常比客户端要早。 为什么需要四次挥手:TCP是全双工的,要保证通信双方都能通知对方需要释放/断开连接(同时服务器还能把必要的数据发送完) 为什么客户端关闭前需要等待2倍的MSL最长报文段寿命(最长报文段生命周期)? 保证连接关闭,避免客户端向服务端发送的最终确认报文超时:为了保证客户端最后发送的连接释放报文能够到达服务器,使服务器能够正常释放连接。对服务器来说,它如果没收到这个报文,会重发一次连接释放确认报文,客户端如果收到了话要重新开始计时2MSL。 阻止延迟数据段,避免接收过期消息:经过了2倍最长报文段寿命的时间而断开连接,可以保证这次连接中所有报文段都从网络中消失,下次连接不会再出现了刚刚被关闭的失效的报文段了。 TCP可靠性(差错控制、流量控制、拥塞控制) 可靠性(流量控制、差错控制(可以不讲)、拥塞控制)从何而来(差错控制:ARQ,流量控制+拥塞控制:滑动窗口(接收窗口、发送窗口)、拥塞控制)? 回答: 首先,采用三次握手四次挥手来建立和释放连接,保证建立的传输通道是可靠的。 其次,TCP使用滑动窗口进行流量控制,保证接收方能够及时处理所接收到的数据;用连续ARQ协议(回退N帧协议(错误帧出现之后,重发这之后的所有帧)、选择重传协议(针对性地重发错误帧);超时自动重传)来保证数据传输的正确性, 差错控制:ARQ自动重传协议,解决出现差错时,让发送方重传差错数据:即 出错重传: 机制 确认-累计确认, 超时重传机制 协议 停等协议(发送、接收窗口都为1) 后退N帧协议(发送大于1,接收为1) 选择重传协议(两个窗口都大于1(接收方具有缓存)),针对性重传出错/超时分组。 连续ARQ协议对应的是停止-等待协议,后者规定发送一个分组就得停止等待对方的确认信号,效率很低。前者则是直接发送连续的几个分组,而接收方也可以一次性接收多个分组。 最后,它用慢开始、拥塞避免、快速恢复、快速重传来进行一个拥塞控制,避免网络拥塞。 拥塞标志: 超时重传:较严重的拥塞 接收三次重复ACK:较轻的拥塞 (拥塞窗口) 滑动窗口:滑动窗口是传输层用于流量控制和保证可靠性的一种措施,简单来说就是,在建立TCP连接过程中发送SYN报文的时候,这个报文里的接收窗口大小信息和可选的窗口扩大因子,两个可以确定一个接收窗口。而对方会根据被通告了解到的接收窗口设置自己的发送窗口。这些滑动窗口实际上表现为缓冲区,一旦缓冲区被填满,它就不会再发送或者接收。对于发送窗口,发送窗口接收到相应的确认信号才会移动窗口;对于接收窗口,除非前面部分的所有连续字节都被收到,窗口才会移动,这里是因为很可能收到乱序的字节。 接收窗口:建立连接时,确认的是最大接收窗口(接收窗口大小字段+可选的窗口扩大因子)。而在正式传输数据的时候,接收窗口大小字段对用的是当前接收窗口大小,等于最大接收窗口大小与已接收和确认但尚未被应用程序检索的数据量之间的差值。 TCP零接受窗口死锁:当接收端向发送端发送零窗口报文段之后不久,缓冲区有了一些空间,于是通知发送方它的接受窗口不再是0了,这个通知报文段丢失了。于是发送端就会认为对方没有接收窗口,等待着变化;而接收端则在等发送端发送数据。 解决死锁:一旦收到0窗口通知,启动一个持续计时器,如果这个计时器的时间到期,就发送一个携带1字节数据的零窗口探测报文段,对方可以在确认这个报文段时给出现在的窗口值。 发送窗口:取决于接收方的接收窗口和拥塞窗口的较小值。发送端只能发送位于窗口内的字节流中的字节,收到对应的确认信息之后窗口才能滑动。 image-20200329115959567 拥塞控制:拥塞控制就是防止网络拥塞。TCP中有两种常用的网络拥塞标志,分别是 计时器超时 和 接收三次重复ACK。(Variable:拥塞窗口与慢启动阈值) 慢启动算法:而拥塞控制的手段主要是通过在本地维护一个CWND拥塞窗口和对应的慢启动阈值。拥塞窗口的初始值一般是最大报文段长度的整数倍。一旦拥塞窗口大小低于慢启动阈值,就使用慢启动算法;高于了话,就使用拥塞避免算法。慢启动就是说,拥塞窗口在每接收到一个确认包(RTT)时增加,一般增加是以最大报文段长度MSS为单位(不过它不完全是指数增长,因为接收方经常接收多个报文段才发送一次确认); 拥塞避免:一旦成长大于慢启动阈值,就会换成拥塞避免算法。这下了话,每次整个窗口的数据都被确认,才加一个MSS。(加法增大) 快速重传:因为接收方每次受到乱序/丢包的报文就会立即多发送一个重复的ACK来提醒发送方,因此发送方收到三次重复ACK时就会认为这个网络有程度较轻的拥塞,就会快速重传序号等于ACK的报文。如,发送1235,收到确认号4;发送6,共12356,还是收到确认号4;发送7…,还是收到确认号4,此时就快速重传。 (在快速重传之后)快速恢复:快速恢复就是说,发送方收到三个冗余重复确认,就把慢启动阈值减半,执行拥塞避免算法,重置拥塞窗口大小等于慢启动阈值+3,+3表示有3个“老”的数据包离开了网络。 超时的处理:发生超时时,减半慢启动阈值,并将拥塞窗口大小重新初始化。(乘法减少)当然,还需要超时重传。 流量控制(滑动窗口) 什么情况下可能引发死锁?如何避免死锁发生? TCP长连接的keep alive(对应HTTP1.1+的持久连接) 和应用层的心跳机制 Keep alive:在传输层,并不在TCP协议中,需要操作系统配置。开启这个机制之后,一定时间内链路没有数据传输时,就会多次发送探针探测连接是否可用。 心跳机制:实现在应用中,客户端开启一个定时任务,定时发送心跳请求,如果没收到对应的响应,就会结束连接。 SYN Flood攻击原理 利用TCP协议缺陷,发送大量半连接请求,让很多请求加入服务器的未连接队列。就是三次握手中,攻击方伪造大量IP发送第一次的连接请求,而不发送第三次,接着服务端就会不停发送第二次的SYN报文请求连接,直到超时才将此条目从未连接队列删除。 半连接、半打开、半关闭 半打开:TCP一端崩溃而另一端不知道,或者说在未通知对方的情况下关闭连接。 OS在传输层配置keep alive机制,或是应用层的心跳机制, 或者 Reset也可以规避这种情况。 半关闭:一方发出了Fin,另一方没发出。 半连接:TCP连接过程中,客户端不进行第三次握手。这样会占用服务器资源(SYN Flood攻击),因为服务器会一致超时重传;直到一定时间后才将此连接从未连接队列中删除。 UDP 简单谈一下UDP:它是无连接(不需要维护连接意味着它可以轻松地向多台客户机发送相同的消息,意味着它支持一对多,支持广播,而且不需要维持连接的开销)的、不可靠的、尽最大努力交付的(就是说它没有流量控制和拥塞控制,吞吐量基本只受两边机器和程序的性能限制)的、面向报文(就是说应用层给它多长的报文它不拆分也不合并,只是添加一个UDP首部之后就向IP层交付)的传输协议。 TCP与UDP的区别:TCP是面向连接的(点对点),提供可靠交付,面向字节流(把应用层交付的数据)、全双工、有流量控制和拥塞控制的数据传输协议。 包头结构: 源端口 16位、目的端口 16位、长度 16位、校验和 16位 与TCP的异同 无连接、有界的特性 常见的应用程序(UDP适用于不需要或者在应用层执行错误检查和纠正的应用,避免了这类处理开销,降低了延迟): DNS、DHCP 网络层网络层的任务:转发与路由网络层的任务是将数据包从发送主机传输到接收主机。举个例子,在发送端,网络层接收来自传输层的段,封装之后将其传入发送端路由器,发送端路由器路由寻路到接收端主机,把数据逐步传到路径上的路由器直到到达接收端主机。 具体地,可以分为两个任务,转发和路由。 转发:转发是路由器的局部动作,指将数据包从路由器的接收链路接口传到输出链路接口的过程。如何选择输出链路接口,主要依赖 转发表。转发表由如下这种键值对组成:键是数据包的首部,值是对应的输出数据链路的索引。也就是说,转发表维护 数据包 到 对应输出链路 的映射。 转发表与路由的关系:转发表通常由路由算法(不论是中心化的还是去中心化的(分布式))计算得到。 路由:路由是指确定发送主机到接收主机的路径的过程。路由算法就是这样一种寻路算法,细节上,路由算法通过维护转发表来实现。 路由算法:(To be continued…) image-20200501215711272 设备与内部细节包交换机packet switch:包交换机指这样一种数据包交换设备,这个设备将数据包从输入链路接口传输到对应的输出链路接口,具体的决定数据包对应哪一个输出链路接口,通过数据包的首部信息来决定。通常是建立一个数据包到对应输出链路接口的映射表。 当数据包为数据报时,就是路由器,属于网络层设备。 到数据包为链路帧时,就是链路层交换机,属于数据链路层设备。 IP协议数据报结构 image-20200501232620561 以上是IPv4的数据报结构。虽然乏味,每个程序员都应该懂… 版本号Version:每个版本的IP数据包结构都不同。 首部长度:因为options(可选项)的存在,需要指定首部长度来确定Data部分开始的位置(TCP协议也是如此) 服务类型:用于区分不同类型的数据报。例如,实时的IP电话或者非实时的FTP传输。 数据报长度:字面意思,上限是65535bytes,不过通常不会超过1500bytes长。 Identifier, flags, fragmentation offset :用于IPv4的IP碎片化 TTL:确保数据包不会在链路中无限循环。TTL在每经过一个路由器减1,当TTL为0时drop数据报。 Protocol协议号;仅在到达接收端时启用。用于指明向上传输时使用哪个传输层协议。例如,6对应TCP,17对应UDP。它是网络层与传输层的接合点,就像端口号是传输层与应用层的接合点一样。 16位首部校验和:仅仅用来校验首部。报头校验和的计算方法是将报头中的每个2字节作为一个数字,并使用1s补数算法将这些数字相加。 源地址与目标地址:字面意思。 可选项options:一定要注意引入可选项时的开销。 IPv4寻址IP地址与接口绑定,而不是与主机或路由器绑定。 image-20200502001355220 接口指 主机与物理链路的边界 或 路由器与物理链路的边界。因为每个主机和路由器都能够发送和接收IP数据报,所以IP需要每个主机和路由器接口都有自己的IP地址。每个公网上的接口都有自己的全球唯一IP(除开NAT协议后的接口)。不过,接口的一部分IP地址将由它所连接的子网决定。 IPv4地址是32bit数,通常采用 点分十进制计数法来分析。 以太网有线连接和无线连接都是实现局域网的方式。 子网:要确定子网,将每个接口从它的主机或路由器上分离,创建孤立网络的孤岛,用这些接口终止孤立网络的端点。每一个孤立的网络被称为子网。 如下图所示。 子网地址与子网掩码:对于下图最上方的子网而言,有(子网)地址223.1.1.0/24 。/24表示子网掩码,表示子网内任意地址的前24位定义了子网地址。 子网内的任意机器都必须有相同的子网掩码和子网地址。 image-20200502002528096 因特网地址分配策略:CIDR(无类域内路由选择) 与 有类路由寻址Classful Addressing CIDR特点;可变长子网掩码 + 前缀路由聚合 网络/主机的划分可以在地址内的任意位置进行。这个划分可以是递归进行的,可以通过增加掩码位数,来使一部分地址被继续分为更小的部分。通过 前缀路由聚合,将连续网络聚合在一起,可以大大减少对外显示的网络数。 连续地址段的获取和 具体的分配(DHCP)连续地址段的获取: 联系ISP(互联网服务提供商) 联系ICANN(互联网名称和数字地址分配机构) 某个组织获取连续地址段之后,如何将其细分给具体的主机和路由器接口:DHCP协议(动态主机配置协议)。 DHCP的功能: 为网络中的主机、路由器接口提供持久或临时的IP地址。 除了让主机知道自己的IP地址,还让它知道自己的 子网掩码、第一条路由(默认网关)、本地DNS服务器。 应用场景:DHCP作为一个即插即用协议,在使用网络的用户来去频繁的场合(例如公共无线网络)和连接网络用户的高峰值低于总用户数时(此时可以维护一个可容纳网络用户峰值的IP地址池),可以节省IP地址数和网络管理员的人力。 实现细节:对于一个试图加入网络的新主机,从试图加入到获取IP配置信息大致有如下四个步骤: DHCP discovery:通过UDP协议,广播发送discovery message,通过链路层传给子网上的所有节点。 DHCP server offers:DHCP服务器广播发送DHCP offer message,包含接收到的discovery message的事务ID、分配的IP地址、子网掩码和IP地址租用时间(IP地址有效的时间量)。 这一步是广播的原因主要是客户主机还没有IP地址,如果它配置能接收来自IP地址为ANY的单播信息了话,那么其实单播也可以。通常来说还是广播,设置“BROADCAST flag = 1”,主机就只接收广播信息。 DHCP request:一个主机可能收到来自不同DHCP 服务器的不同offer,主机将选择一个,并广播发送请求。这一广播可以让其他DHCP服务器重置状态而不必继续考虑与该主机的通信。 DHCP ack:DHCP服务器对来自主机的DHCP request给出应答。 image-20200502103029189 NATNAT(网络地址转换)协议用于解决IPv4地址短缺的问题。它将多个私网IP映射到一个公网IP上。 内网地址:10.0.0.0/8, 172.16.0.0/12,196.168.0.0/16 如何给局域网内的机器分配私网地址?仍旧是 DHCP 如何定位局域网内的机器?NAT转换表。如下图所示,通过端口来定位主机,只要保证外部接口的临时端口号不重复就好了。 举个例子,下图中三台机器都想要对外提供SSH服务,开启22端口,它们对应的WAN side IP是一致的,不过却有着不同的端口,这样就可以区分开来了。 优势: 节省IP资源 对外隐藏内网细节,安全。 弊端: 端口本应用来寻址进程,NAT中却被用来寻址主机。这样会给运行在内网里的服务器带来一些麻烦,比方说提供常用的固定IP的服务时。 影响P2P 链路层链路层寻址与ARP链路层地址,也称作物理地址或MAC地址。设备在出厂时,其MAC地址就被生成且写死,并被IEEE确认唯一。 通常来说,它与IP地址是一一对应的关系,实质上是它与适配器(网络接口)绑定。 而MAC地址的存在是为了保证各层之间独立运行,这样可以允许支持其他网络层协议(例如IPX或DECnet)。而MAC地址的存在是物理上唯一固定的,而IP地址则是类似邮政编码一样,有层次的,易变的。 对于MAC地址与IP地址的相互转换,就要用到地址解析协议(ARP)。 ARP不同于DNS,它只为在同一子网上的主机和路由器接口解析IP地址,否则就报错。 工作方式: 每台主机/路由器在内存中维护一个ARP表,这张表包含子网内网络适配器对应的IP地址到MAC地址的映射关系和过期时间(TTL)。 在表中没有对应映射时,发送方将通过MAC广播地址(FF-FF-FF-FF-FF)来发送ARP分组。每个收到广播的适配器都检查自己的IP地址是否与ARP分组中的目的IP地址匹配,与之匹配的就返回 响应ARP分组,令查询方更新它的ARP表。 ARP查询是广播帧,因为不知道目标IP的位置,也不知道其是否存在。ARP响应则是标准帧。 ARP是即插即用的,它自动建立,不需要人工配置。 ARP协议属于跨越网络层和链路层两边的协议。","tags":[]},{"title":"数据结构","date":"2020-05-10T12:29:40.785Z","path":"2020/05/10/数据结构与算法/","text":"查找与排序二分查找 二分查找,要熟悉迭代与非迭代的写法, 以及对各种边际条件的考量 变种:可以使用floor和ceil确定它的上下界 当存在大量重复的元素时,floor找的是第一个,ceil找的是第一个。 当不存在指定的元素时,floor是比其小最大的一个,而ceil是比其大最小的一个。 算法:先找到对应值,然后再使用二分查找寻找上下界(floor或ceil可作为二分的巩固练习) 二分查找的应用 跳表(基于链表的二分查找),redis的有序集合 二叉搜索树 有序序列 快排、归并、堆排 JAVA源生查找算法 Arrays.binarySearch(list,key); Collections.binarySearch(List sList, T key, Comparator C) :根据是否实现了Comparable接口 进阶:基于搜索下标空间的二分和基于值范围的二分:求数组中第n大的元素 基于值的二分:当重复值较少且值的范围不大时,可以对值域进行二分查找。在这个问题中各方面来看都不是个好方法,不过要知道思路。 常规的二分思路的应用,在这里是快排partition思想的应用,partition的特点是每次能确定pivot的绝对位置并约束其左右序列的值域,应用在搜索中就是快速选择算法,平均时间复杂度O(n),最坏时间复杂度O(n^2),一般来说是一种很好的无序查找第k元素的方法。 快速选择与三路快排:https://leetcode-cn.com/problems/wiggle-sort-ii/ Partition 的两种版本:见LC 215 交替赋值法 交换法(不使用while(true)的版本) 排序 十种排序算法 (最坏、平均、最优)时间复杂度、空间复杂度 image-20200309194909228 排序稳定性的意义1. 对于int[],确实意义不大;但对于复杂对象,**原始数据的相对关系**可能具有更深的逻辑意义;例如按身高排序,体重的相对关系不应该变化 1. 因此,源生的排序算法,对基本类型是(三路)快排,而复杂类型则是归并排序保证稳定性 哪几种排序支持并行? 冒泡排序-》奇偶排序,可并行 归并排序->基于msg的分布式系统。比较特殊,在各自的机器内使用快排排好,然后再merge。 快速排序 img 分治算法——侧重于分。 观察快排递归树,二路快排对大于等于是一样的处理,这意味着在重复值较多的情况下,快排递归树会极度不平衡。 为此而生的就是三路快排,以下是它的parition实现。 image-20200414185401728 1234567891011121314151617181920212223242526//Key:明晰并维护变量的逻辑含义// left,right都表示partition范围的实边界public int[] partition(int[] nums, int left, int right) { int pivot = nums[right]; int lt = left - 1, rt = right; int i = left; // lt,rt的定义是小于pivot和大于pivot的值的 实边界 while (i < rt) { int num = nums[i]; if (num < pivot) { swap(nums, i , ++lt); i++; } else if (num > pivot) { swap(nums, i, --rt); } else { i++; } } swap(nums, right, rt++); int[] bound = new int[2]; bound[0] = lt; bound[1] = rt; return bound; } 归并排序分治算法 – 计算的过程主要在合并中。 归并排序应用在计算逆序对中的例子。需要注意的是归并排序需要额外空间来维护排序过程中的左右序列下标i,j的语义,也因此,它视为out-place排序。 12345678910111213141516171819202122232425262728293031private int mergeAndCount(int[] nums, int left, int mid, int right, int[] temp) { // 复制到辅助数组里,帮助我们完成统计 for (int i = left; i <= right; i++) { temp[i] = nums[i]; } int i = left; int j = mid + 1; int res = 0; for (int k = left; k <= right; k++) { if (i > mid) { // i 用完了,只能用 j nums[k] = temp[j]; j++; } else if (j > right) { // j 用完了,只能用 i nums[k] = temp[i]; i++; } else if (temp[i] <= temp[j]) { // 此时前数组元素出列,不统计逆序对 nums[k] = temp[i]; i++; } else { // 此时后数组元素出列,统计逆序对,快就快在这里,一次可以统计出一个区间的个数的逆序对 nums[k] = temp[j]; j++; res += (mid - i + 1); } } return res; } 优化针对近乎有序的数组,在merge前可以判断一下list1的尾巴和list2的头,如果符合有序性那么就可以不merge了。 在即将排序完成时,可以转而使用插入排序。 应用并行排序、求逆序对。 本章节知识体系与复习思路Talk is not cheap 了解各类排序算法的思想和应用场景,自然就明白其时空复杂度 熟悉二分思想,尤其明白它如何在跳表和各种二叉搜索树变形中应用 能解TOP K问题,能用擅长的语言熟练地对任意数据类型排序(例如,在Java中,要会写比较器) Show the Code 手写floor 手写三路快排、归并、堆排 通过TOP K问题(LC 215)、排序(LC 912) 练习 树满二叉树与完全二叉树对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。(每层结点都完全填满,在最后一层上如果不是满的,则只缺少右边的若干结点。) 鉴于完全二叉树的性质,它可以很容易地被数组表示,通过数组下标间关系可以观察到父子关系。 堆堆不一定是完全二叉树(可以是其他树),使用完全二叉树实现堆是因为易于存储且便于索引。 常用的是二叉堆是具有父结点大于等于/小于等于子结点的完全二叉树。 核心操作 堆化:检查某个非叶子结点是否符合堆特性,在交换完毕之后需要接着递归地去检查交换过后的新结点 建堆:从最后一个非叶子结点倒序遍历至根节点,每次都进行堆化 插入:每次在数据末端插入,之后进行siftup(),找到插入结点的父结点并检查父子关系是否需要交换;接着迭代地检查移动后的新插入结点与其父亲的关系 删除:用最后一个元素替代要删除的元素,接着siftdown() ,类似siftup,直到都符合堆条件 LC:见https://cloud.tencent.com/developer/article/1163053整理 劣势: 对复杂数据的swap开销较大 建堆前和建堆后,难以找到原先位置的元素。比方说,想找原来索引值为6的元素,建堆后就只能遍历找了。 索引堆建立两个数组,树索引 -> 原始数据; 树索引 -> 建堆后的元素索引。想找建堆后的数据就从 树索引-> 建堆后的元素索引号-> 数据。 image-20200416150548989 image-20200416150602565 实现与应用Java类:PriorityQueue 进程调度的一种实现:优先队列用于选择优先级最高的任务 在N个元素中选前M个大元素:O(MlogN),维护一个最小堆,当元素比最小堆堆顶大时删除堆顶,让它进堆。 多路归并排序:可以在merge的时候用堆排序 最大最小队列(同时能找到最大元素和最小元素的优先队列):利用两个索引堆 二分搜索树 核心定义:左子树的所有值都比根小,右子树的所有值都比根大,不会有重复索引。用于有序查找问题。 性能,O(logn)-O(n);性能瓶颈在于极端不平衡的情况;平衡二叉树和红黑树都是它的改进 搜索,插入,删除的复杂度实质上取决于对应结点的深度,二分搜索树的这三个操作效果都不错 查找过程:中序遍历二叉搜索树可以得到一个有序序列 插入过程:递归插入即可 删除过程: 删叶子:直接删除 删仅有单子树:删除,子结点替代原本根结点的位置 删有双子树:用它的直接前驱或者后继A(即左子树的最大结点或右子树的最小结点)替代它,然后再删除A 顺序性: Ceil Floor Rank(一个元素是排名第几的?/二分搜索树的结点个数):对每个结点都存以它为根结点的树的结点数,就可以很轻松地算出来 Select(排名第x的元素是谁?):使用中序遍历即可得 如何支持重复元素?:为每个node加一个默认为1的count,表示重复的次数 AVLAVL: 对比二叉搜索树的改进之处:控制了两边子树的高度差不大于1 性能:时间复杂度都是O(logn) 缺陷:增加或删除元素的操作需要一次或多次的树旋转,以实现树的重新平衡 查找、插入、删除过程 某根结点的平衡因子:该结点左右子树的高度差;可以直接保存平衡因子,或者保存结点的高度 四种情况LL RR LR RL LL 右旋 RR 左旋 LR 先左后右 RL 先右后左 查找和二叉搜索树是一样的 插入和删除之后需要再平衡 B+树红黑树红黑树(可以认为是一种特殊的平衡二叉搜索树) 对比二叉搜索树、AVL的改进之处:控制两边子树的高度差不为2倍(最大深度≤最小深度的两倍),控制力度比AVL小。 性能:类似AVL,不过插入和删除通常比AVL快,但是在查询频繁的环境下可能AVL更快,因为AVL的结点平均高度比较小。每个结点会占用更多的空间。 性质:(作为2-3-4树的一种等价) 结点带黑色或是红色 根结点,叶子结点是黑色 红色结点的子结点是黑色(没有父子都红) 从任意结点到叶子结点的路径都包含了数量相同的黑结点 构建、查找、插入、删除过程: 自平衡过程: 左旋:旋转点N的右结点R作为父结点,R的左结点作为N的新右结点 右旋:旋转点N的左结点L作为父结点,L的右结点作为N的新左结点 变色:变色以符合红黑树性质 插入/删除:查找->自平衡 ,具体见https://www.jianshu.com/p/e136ec79235c Trie树trie树: 用于前缀匹配(例如在搜索引擎中)。利用所有字符串构建trie树,然后输出以target为开头的树即可 线段树应用至少了解以下应用: avl树“windows对进程地址空间的管理” 红黑树(linux中ext3文件系统管理),(JAVA的HashMap的底层实现) B树(数据库)(文件系统) -》确定是哪类数据库和哪类文件系统 哈夫曼树:给定n权值作为n个叶子节点,构造一棵二叉树,若这棵二叉树的带权路径长度达到最小,则称这样的二叉树为最优二叉树,也称为Huffman树。(节点的带权路径长度:从该节点到树根之间的路径长度与节点上权的乘积。) 应用于通信中对信息的二进制编码。令所有字符都位于叶子结点,出现次数多的字符与根的路径长度最短,这样来降低开销。 建树方法:按出现的频率(权值)从小到大建树,父结点的权值为子结点之和。 本章节知识体系与复习思路Talk is not cheap 理解BFS和DFS的思想和侧重的问题,应用思想到二叉树的遍历中 熟悉并且会利用二叉树的性质(例如完全二叉树父结点与子结点的关系,例如结点数目、分支数和叶子结点数目的数学关系) 熟悉堆排序(maxheapify) 了解三种平衡二叉树的变体的应用场景(AVL、B+、红黑) Show the Code 会写二叉树的三种遍历,包括中序和前序的非递归形式 跳表跳表 img 定义:首先,跳表处理的是有序的链表(一般是双向链表)。底层存储全部得结点,每上一层,结点减少一半。搜索时优先搜索上层,然后定位到下层。 优势:维持结构平衡的成本很低,完全依赖随机。 查询,插入,删除的时间复杂度都是O(log N),占用的空间为O(2N) 插入与删除时给链表升降层:随机选择新节点是否提拔,默认概率50% 应用:redis、leveldb 图论组合数学卡特兰数https://brilliant.org/wiki/catalan-numbers/ https://www.zhihu.com/question/25072237/answer/30111179 img 对(k,k+1)将路线分为两部分,后半部分可以将矩阵旋转 观察(0,0)到(n - 1, n + 1),必定经过(k, k+ 1) 故可以求出超过对角线的值 image-20200430101623936 应用基本思路 明确问题(输入->输出,类型与范围限制) 想到一个合适的算法 观察大致的思路,拆解问题,转化成自己解决过的问题 或者从暴力法优化 Coding: 确定大概的逻辑,光速写下注释 确定每个变量的定义,并在算法中维护它 Debug & Test 小数据量调试 边际条件调试 时空复杂度得到大致的时空复杂度并不困难,要达到合格的标准应至少能手推 建堆(而不是堆排序) 的时空复杂度。 海量数据问题难点: 存储空间不足以一次容纳所有数据 传统方法应对海量数据可能过于耗时 https://juejin.im/entry/5a27cb796fb9a045104a5e8c 基本解决方案: 分治(值域分治/实际数据分治)+Hash 位图:用更小的容量来表示每个数据的情况 Trie树:适用于数据量大、重复多、但是数据种类少的情况。例如各种词频统计 MapReduce:一种分布式处理方案 在2.5亿个整数中找到不重复的整数。 分治法+HashMap:将数组分为多批(对数据进行划分或者对数值范围进行划分都是可行的),每批维护HashMap(key为整数,value为出现的次数)。每批处理完之后清洗不合法的key。 位图存储:使用更精简的存储方式来维护整数和它的对应情况。2.5亿个数,每个数可以维护三个情况(1:没有;2:出现一次;3:出现多次),可以用2bit维护它的情况。2.5亿个数耗內存1GB,可以接受。 海量日志数据:提取出某日访问淘宝次数最多的IP 不一样的分治+Hash:这次是对IP范围进行分治,利用Hash映射一次读入一个范围的IP,然后对其进行次数分析,最大堆排序;保存堆顶,在全部IP范围处理完之后,对比堆顶就可以得到结果了。","tags":[]},{"title":"Hello World","date":"2020-04-14T08:39:48.767Z","path":"2020/04/14/hello-world/","text":"Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub. Quick StartCreate a new post1$ hexo new \"My New Post\" More info: Writing Run server1$ hexo server More info: Server Generate static files1$ hexo generate More info: Generating Deploy to remote sites1$ hexo deploy More info: Deployment","tags":[]}]