type
status
date
slug
summary
tags
category
icon
password

HTTP

三次握手

notion image
三次握手是为了防止在网络不好的情况下,客户端多次请求造成数据混乱
序号(Initial ********sequence number):ISN 序号,用来标记数据段的顺序,TCP 把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号;序列号 ISN 就是这个报文段中的第一个字节的数据编号。
确认号(acknowledgement number):ack序号,期待收到对方下一个报文段的第一个数据字节的序号;序列号表示报文段携带数据的第一个字节的编号;而确认号指的是期望接收到下一个字节的编号;因此当前报文段最后一个字节的编号+1即为确认号。
标志位(Flags):共6个,即URG、ACK、PSH、RST、SYN、FIN等。具体含义如下:
  • URG:紧急指针(urgent pointer)有效。
  • ACK:确认序号有效。(为了与确认号ack区分开,我们用大写表示)确认同步。可以看作一个布尔值,1 为 true,0 为 false。
  • PSH:接收方应该尽快将这个报文交给应用层。
  • RST:重置连接。
  • SYN:发起一个新连接。可以看作一个布尔值,1 为 true,0 为 false,发送 SYN 是请求同步(true 我愿意,false 我拒绝)
  • FIN:释放一个连接。
ISN 序号、ack序号:用于确认数据是否准确,是否正常通信。
标志位:用于确认/更改连接状态
第一次握手:主机A发送位码为sf随机产生 seq = 1234567的数据包到服务器,主机B由SYN=1知道,A要求建立联机;
第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的 seq + 1),syn = 1,ACK=1,随机产生 seq = 7654321的包;
服务器端回复的这个+1,是代表他收到了SYN标示。
也就是说由于SYN或者FIN的存在,即使没有数据传输,但服务器端仍然需要通过+1来回应一句“我收到了”。因此握手过程中 seq = x 的话,ack = x + 1。其他几次握手挥手也是同样道理
第三次握手:主机A收到后检查ack number是否正确,即第一次发送的 seq + 1,以及位码 ACK 是否为1,若正确,主机A会再发送ack number=(主机B的 seq + 1),ack = 1,主机B收到后确认 seq 值与ack = 1 则连接建立成功。
如客户端发出连接请求,但因连接请求报文丢失而未收到确认,于是客户端再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接,客户端共发出了两个连接请求报文段,其中第一个丢失,第二个到达了服务端,但是第一个丢失的报文段只是在某些网络结点长时间滞留了,延误到连接释放以后的某个时间才到达服务端,此时服务端误认为客户端又发出一次新的连接请求,于是就向客户端发出确认报文段,同意建立连接,不采用三次握手,只要服务端发出确认,就建立新的连接了,此时客户端忽略服务端发来的确认,也不发送数据,则服务端一致等待客户端发送数据,浪费资源。
这里在补充一点关于 SYN-ACK 重传次数 的问题: 服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传。如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。 注意,每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为 1s,2s,4s,8s......
三次握手过程中可以携带数据吗?
其实第三次握手的时候,是可以携带数据的。但是,第一次、第二次握手不可以携带数据
为什么这样呢?大家可以想一个问题,假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂着重复发 SYN 报文的话,这会让服务器花费很多时间、内存空间来接收这些报文。
也就是说,第一次握手不可以发数据,其中一个简单的原因就是会让服务器更加容易受到攻击了。而对于第三次的话,此时客户端已经处于 ESTABLISHED 状态。对于客户端来说,他已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的了,所以能携带数据也没啥毛病。

四次挥手

notion image
第一次挥手:
客户端发起关闭请求,发送 FIN (释放连接),seq = u(随机产生)。客户端更改状态为 FIN_WAIT1,服务器状态为 ESTABLISHED
第二次挥手:
服务器收到 FIN 指令,回复大写 ACK 告诉客户端收到指令并确认,生成 seq = v(随机产生)、小写 ack = u + 1(客户端发的 seq + 1),告诉客户端已经收到指令了。客户端更改状态为 FIN_WAIT2,服务器状态为 CLOSE_WAIT
第二次挥手的原因是tcp的MTU一般是1500个byte,除去头只剩下1400多个byte,也就是1m多的数据,所以存在粘包断包等现象,可能一个tcp包没发完,不像udp有数据边界(蓝牙socket同理)
第三次挥手:
服务器在确定自己不再发送数据时,发送 FIN 释放连接,ACK 确认指令 = 1,seq = w(再次随机产生),ack = u + 1。客户端状态依然为 FIN_WAIT2,服务器状态为 LAST_ACK
第四次挥手:
客户端收到 FIN 指令,回复大写 ACK 告诉服务器收到指令并确认,发送 seq = u + 1(这是我自己的数据),ack = w + 1(这是你的数据)。
客户端进入 TIME_WAIT 状态,也叫 2MSL 状态,并在 后进入 CLOSED 状态,服务器收到报文后进入 CLOSED状态。
每个具体TCP实现必须选择一个报文段最大生存时间MSL(Maximum Segment Lifetime),它是任何报文段被丢弃前在网络内的最长时间
如果此时服务器没有收到第四次报文,服务器会在 2 个 MSL 时间内重新发送 FIN 报文,如果此时客户端直接断开了连接而没有等待,会造成服务器无法正常关闭连接的问题
等待 2 个 MSL 时间也是在等待本次连接中产生的所有报文消失,以免影响下一次连接
挥手为什么需要四次?
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送 SYN + ACK 报文。其中 ACK 报文是用来应答的,SYN 报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭 SOCKET,所以只能先回复一个 ACK 报文,告诉客户端,"你发的FIN报文我收到了"。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
notion image

HTTPS = HTTP + SSL(或TLS):

对称加密:
对称加密就是客户端和服务器的加密解密方式一致,缺点是只要中间者知道了加密方式,就可以进行解密
非对称加密:
非对称加密就相当于服务器有一个钥匙(私钥),和无数个这把钥匙可以打开的、可以直接扣下上锁的锁(公钥),在请求时,服务器把锁(公钥)带上盒子发送给客户端。客户端拿到带锁的盒子(公钥)后,把数据放盒子里,扣上锁,最后交给服务器。服务器有钥匙(私钥)就可以解锁了
notion image
notion image

Charles抓包流程:

我们已经知道了 https 的通信流程,在 Charles 抓包前,需要在手机上安装一个证书,其实就是 Charles 的公钥
我们之前请求 www.baidu.com 的流程是:
主机上的 dns 对百度进行解析,解析出真实 ip 地址,http 默认端口号是 80,https 默认端口号是 443,有了 ip 和 端口号,就等于 socket 连接,之后三次握手,https 的话要传公钥证书,最后开始通信
现在我们安装了 Charles 的证书,我们相当于向 Charles 进行请求了,Charles 抓包前,我们需要在手机 Wifi 设置里设置 Wifi 代理为手动,填上电脑的 ip 地址,Charles 的端口号。ip 加端口号依然是 socket 连接了
连接了之后,我们发送到所有请求都是发给了 Charles,所以 Charles 抓到了我们要发送的数据。
Charles 之后会对我们要请求的地址和内容发送给真正的服务器,服务器会把要返回的数据发送给真正的请求者 Charles,Charles 也就拿到了服务器返回的数据。最终我们请求的 Charles 会把收到的数据返回给我们
这就完成了整个 Charles 的抓包流程
Hash 函数和 Hash 表UIButton 扩大点击事件的三种方式