一、前语
温习网络协议核心常识,进一步夯实根底,为后边 参加物联网、音视频、直播等范畴的项目做必定的常识储藏。
二、序号、承认号
发送HTTP恳求前先树立衔接(三次握手):
发送方发送数据时,并不是每次发送TCP段都需求发送承认信号的,上图中每段都发送承认信号仅仅为了让我们更好的了解发送流程。
序号是发送方为了让接纳方知道当前发送的是哪一块数据。真实的序号并不是从1开端的(相对值),而是一个很大的值(原始值),只不过为了便利记忆及学习,wireshark现已核算处理。
序号是在树立衔接时现已承认的。
ACK号是接纳方奉告发送方下一次发送数据从哪一个字节开端。
序号原始值为什么不能从1开端(简略值)?
为了安全。当序号十分简略时,能够通过抓包得知下一个要发的包是什么,然后模拟包数据进行传输。
1. 序号和承认号交互流程
树立衔接时只有前两次的SYN是1(SYN=1
),后边的SYN都是0(SYN=0
)。衔接树立后(三次握手)开端正式发送HTTP恳求。
在实际的传输过程中序号的初始值并不会是1,而是一个随机数避免被猜测和被利用。看一下ACK号和序号传输过程:
然而传送数据是双向的,服务端也会向客户端发送数据,客户端核算出初始序号然后与数据一同发给服务端,服务端收到后核算ACK号再回来去。而服务端也需求核算出一个自己的初始序号,与数据一同发送给客户端,然后客户端得出ACK回来给服务端。
这样两边都奉告了对方自己的初始序号并开端传送数据,过程如图:
客户端和服务器的序号初始值都是在TCP树立衔接时承认的(值是随机的),并且会互相奉告对方的序号。开端收发数据时,客户端的序号便是Seq = 上次客户端的序号(第一次是初始值) + TCP段字节序号
,TCP段字节序号指的是TCP段的第几个字节,是一个相对值。服务器的ACK号便是ACK = 客户端的Seq + TCP段长度
。服务端向客户端发送数据同理(用的是服务器的序号初始值)。
比方客户端的序号初始值是123456
,服务器的序号初始值是56789
。衔接树立后,客户端发送的第一个包的序号便是Seq = 123456 + 1 = 123457
,假设TCP包长度Length
是100个字节,服务端的ACK号便是:ACK = Seq + Length = 123557
。
发送方的序号和接纳方的承认号都使用的是发送方的序号初始值。
把原始值s1和s2去掉,剩余的部分便是相对值。
三、树立衔接(三次握手)
-
CLOSED
:client处于封闭状况。 -
LISTEN
:server处于监听状况,等候client衔接。 -
SYN-RCVD
:表明server接纳到了SYN报文,当收到client的ACK报文后,它会进入到ESTABLISHED
状况。 -
SYN-SEND
:表明client已发送SYN报文,等候server的第2次握手。 -
ESTABLISHED
:表明衔接现已树立。
前2次握手的特色:
- SYN都设置为1
- 数据部分的长度都为0
- TCP头部的长度一般是32字节,固定部分是20字节,选项部分是12字节
两边会交换承认一些信息,比方MSS、是否支持SACK、Window scale(窗口缩放系数)等。这些数据都放在TCP头部的选项部分中(12字节)。
为什么树立衔接的时分,要进行3次握手?2次不行么? 首要目的是避免server端一直在等候,浪费资源。
- 假如树立衔接只需求2次握手。假设client宣布的第一个衔接恳求报文段,因为网络推迟,在衔接开释以后的某个时刻才到达server。
- 原本这是一个早已失效的衔接恳求,但server收到此失效的恳求后,误认为是client再次宣布的一个新的衔接恳求,所以server就向client宣布承认报文段,同意树立衔接;
- 假如不选用3次握手,那么只需server宣布承认,新的衔接就树立了;
- 因为现在client并没有真实想衔接服务器的意愿,因此不会理睬server的承认,也不会向server发送数据;
- 但server却认为新的衔接现已树立,并一直等候client发来的数据,这样server的许多资源就白白浪费掉了。
选用三次握手的方法就能够避免上述现象的发生。例如上述状况,client没有向server的承认宣布承认,server因为收不到承认,就知道client并没有要求树立衔接。
第三次握手失败了,会怎么处理?
- 此刻server的状况为
SYN-RCVD
,若等不到client的ACK
,server会从头发送SYN+ACK
包; - 假如server屡次重发
SYN+ACK
都等不到client的ACK
,就会发送RST
包,强制封闭衔接。
四、开释衔接(四次挥手)
-
FIN-WAIT-1
:表明想自动封闭衔接。- 向对方发送了FIN报文,此刻进入到
FIN-WAIT-1
状况。
- 向对方发送了FIN报文,此刻进入到
-
CLOSE-WAIT
:表明在等候封闭。- 当对方发送FIN给自己,自己会回应一个ACK报文给对方,此刻进入到
CLOSE-WAIT
状况。 - 在此状况下,需求考虑自己是否还有数据要发送给对方,假如没有,发送FIN报文给对方。
- 当对方发送FIN给自己,自己会回应一个ACK报文给对方,此刻进入到
-
FIN-WAIT-2
:只需对方发送ACK承认后,自动方就会处于FIN-WAIT-2
状况,然后等候对方发送FIN报文。 -
CLOSING
:一种比较罕见的例外状况。- 表明你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。
- 假如两边几乎在一起准备封闭衔接的话,那么就呈现了两边一起发送FIN报文的状况,也即会呈现
CLOSING
状况。 - 表明两边都正在封闭衔接。
-
LAST-ACK
:被迫封闭一方在发送FIN报文后,最后等候对方的ACK报文。当收到ACK报文后,即可进入CLOSED
状况。 -
TIME-WAIT
:表明收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可进入CLOSED
状况。- 假如
FIN-WAIT-1
状况下收到了对方一起带FIN标志和ACK标志的报文时,能够直接进入到TIME-WAIT
状况,而无须通过FIN-WAIT-2
状况。
- 假如
-
CLOSED
:封闭状况。
因为有些状况的时刻比较短暂,所以很难用netstat
命令看到,比方SYN-RCVD
、FIN-WAIT
等。
为什么开释衔接要通过TIME-WAIT
状况?能直接开释么? TCP/IP协议栈在设计上,允许任何一方先发起断开恳求。这里演示的是client自动要求断开的。
client发送ACK后,需求有个TIME-WAIT
阶段,等候一段时刻后,再真实封闭衔接。一般是等候2倍的MSL(Maximum Segment Lifetime,最大分割生计期)。MSL是TCP报文在Internet上的最长生计时刻,每个详细的TCP完成都必须挑选一个承认的MSL值,RFC1122建议是2分钟。能够避免本次衔接中发生的数据包误传到下一次衔接中(因为本次衔接中的数据包都会在2MSL时刻内消失)。
假如client发送ACK后立刻开释了,然后又因为网络原因server没有收到client的ACK,server就会重发FIN。这时或许呈现的状况是:
- client没有任何呼应,服务器那儿会干等,甚至屡次重发FIN,浪费资源。
- client有个新的应用程序刚好分配了同一个端口号,新的应用程序收到FIN后立刻开端执行断开衔接的操作,原本它或许是想跟server树立衔接的。
client在TIME-WAIT
状况下,首要是等候server是否会持续发送FIN(避免client的ACK丢包)。
为什么开释衔接的时分,要进行4次挥手? 首要原因是:TCP是双工模式。
-
- 第1次挥手:当主机1宣布FIN报文段时
- 表明主机1奉告主机2,主机1现已没有数据要发送了,可是此刻主机1仍是能够接纳来自主机2的数据
-
- 第2次挥手:当主机2回来ACK报文段时
- 表明主机2现已知道主机1没有数据发送了,可是主机2仍是能够发送数据到主机1的
-
- 第3次挥手:当主机2也发送了FIN报文段时
- 表明主机2奉告主机1,主机2现已没有数据要发送了
-
- 第4次挥手:当主机1回来ACK报文段时
- 表明主机1现已知道主机2没有数据发送了,随后正式断开整个TCP衔接