TCP报文段的首部格式介绍

源端口:占 16位2个字节发起通信的那个进程

目的端口:占 16位2个字节接收通信的那个进程

序号(seq):占 32位4 个字节,序号范围[0,2^32-1],序号增加到 2^32-1 后,下个序号又回到 0。TCP 是面向字节流的,通过 TCP 传送的字节流中的每个字节都按顺序编号,而报头中的序号字段值则指的是本报文段数据的第一个字节的序号。例如:我们的seq = 201,携带的数据有100,那么最后⼀个字节的序号就为300,那么下⼀个报⽂段就应该从301开始.

确认号(ack):占 32位4 个字节,期望收到对方下个报文段的第一个数据字节的序号。当标志位ACK值为1时,才能产生有效的确认号ack。并且:ack=seq+1;

RST:当RST=1时,表明TCP连接出现严重错误,此时必须释放连接,之后重新连接,⼜叫重置位.

URG:紧急指针标志位,当URG=1时,表明紧急指针字段有效.它告诉系统中有紧急数据,应当尽快传送,这时不会按照原来的排队序列来传送.⽽会将紧急数据插⼊到本报⽂段数据的最前⾯

ACK:当ACK=1时,我们的确认序列号ack才有效,当ACK=0时,确认序号ack⽆效,TCP规定:所有建⽴连接的ACK必须全部置为1

PSH:推送操作,提示接收端应用程序立即从TCP缓冲区把数据读走

SYN:同步序列号标志位,tcp三次握⼿中,第⼀次会将SYN=1,ACK=0,此时表⽰这是⼀个连接请求报⽂段,对⽅会将SYN=1,ACK=1,表⽰同意连接,连接完成之后将SYN=0

FIN:在tcp四次挥⼿时第⼀次将FIN=1,表⽰此报⽂段的发送⽅数据已经发送完毕,这是⼀个释放链接的标志

PS:ACK、SYN和FIN这些大写的单词表示标志位,其值要么是1,要么是0;ack、seq小写的单词表示序号

16位窗⼝的⼤⼩:win的值是作为接收⽅让发送⽅设置其发送窗⼝⼤⼩的依据.

紧急指针:只有当URG=1时的时候,紧急指针才有效,它指出紧急数据的字节数.

三次握手

三次握手,顾名思义就是客户端与服务端进行三次通信。 刚开始客户端处于关闭(Closed)状态,服务器处于监听(Listen)状态。

**第一次握手 : **客户端给服务器发送SYN报文,初始的序列号为x,并且需要消耗一个序号。此时客户端进入SYN_SENT状态。 当SYN=而ACK=时,表明这是一个连接请求报文。 注意SYN=1时的报文段是不能携带数据的,因此第一次握手和第二次握手客户端和服务端都不能携带数据。 这是因为如果可以携带数据的话,假如有人想要攻击服务器,只需要每次在第一次握手时在SYN报文放入很多数据,重复发送这些大量的SYN报文,服务器就会花大量内存缓冲这些报文,服务器就更加容易被攻击了。

第一次握手服务端可以看出 :客户端的发送能力,和自己的接收能力处于正常状态

**第二次握手:**服务端收到来自客户端的SYN报文后,对这个SYN报文确认后,会把自己的SYN报文响应给客户端,此时ACK=1表示确认序列号有效,SYN=1也不能携带数据,并且确认号(ack)的值为传来的seq+1,即为x+1,此时初始序号为y。此时服务器进入SYN_RECV状态

第二次握手客户端可以看出:服务端的发送和接收能力都正常,客户端的发送和接收能力也都正常,但重要的一点是服务端不知道客户端的接收能力是否正常。

**第三次握手:**客户端收到了服务器SYN+ACK的包,此时客户端处于ESTABLISHED状态并且客户端和服务端均表示同意连接,因此会发送一个ACK报文,确认号ack的值仍为序列号+1,即y+1,初始seq值为x,所以第二个报文段seq+1,即x+1。

第三次握手可携带数据,不携带数据则不消耗数据

第三次握手可以看出: 客户端的发送接收,服务端的发送接收能力均正常。

两次握手为什么行不通

主要是避免重复连接,比如在网络环境比较复杂的情况,客户端可能会连续发送多次请求。如果只设计成两次握手的情况,服务端只能一直接收请求,然后返回请求信息,也不知道客户端是否请求成功。这些过期请求的话就会造成网络连接的混乱。解决了网络信道不可靠的问题,为了能在不可靠的信道上建立可靠的连接需要三次握手

另外,三次握手是安全的,并且节约资源

如果客户端发送请求时出现了丢包情况,因为自己没发送,又重新传了一遍,然而等数据传输完成后客户端和服务端都释放了连接,第二次传输的数据在释放连接前给服务器传了过去,但第一次传输的数据假如由于网络原因滞留的时间长了,在释放连接后到达了服务端,这个时候服务端就会误以为客户端又发出了一次新的请求,服务端确认了客户端第一次发出的报文段并同意建立了新的连接,发送报文给客户端,此时服务端会一直等待客户端的答复,而客户端此时正处于释放连接状态,所以导致白白浪费了资源。

四次挥手

四次挥手,顾名思义就是客户端和服务端四个步骤的释放连接,断开连接需要发送四个包,别名连接终止协议。由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。 刚开始客户端和服务端都处于ESTABLISHED状态,假如客户端主动发起关闭请求:

**第一次挥手:TCP客户端向服务端发送一个FIN报文,用来关闭客户端到服务端的数据传送,其中包含一个序列号seq=u,发送完后,客户端进入FIN_WAIT_1状态,**即主动关闭TCP连接,不再发送数据,(但是可以接收服务器发来的报文),等待服务端回复。

**第二次挥手:**服务端接收到FIN报文后,会发回一个ACK,表明自己已经接收到了此报文,(此时客户端接就知道服务端接收到了自己的断开连接请求),(但是服务端可能还有数据要传输),并且seq=v,ack的值为序列号+1,此时服务端进入CLOSE_WAIT关闭等待状态。和SYN一样,一个FIN将占用一个序号。这个时候TCP处于半关闭状态,当客户端接收到服务端的回复后,进入FIN_WAIT_2终止等待2状态。

**第三次挥手:**服务器关闭客户端的连接,发送一个FIN报文给客户端,并且指定一个序列号,ack的值为u+1,此时服务器处于LAST_ACK最后确认状态,等待客户端回应。

**第四次挥手:**客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答(ack = w+1),且把服务端的序列值 +1 作为自己 ACK 报文的序号值(seq=u+1,此时客户端处于 TIME_WAIT(时间等待状态)。TIME-WAIT状态是为了等待足够的时间以确保远程TCP接收到连接中断请求的确认。

关于http和https推荐看这篇文章:https://yebd1h.smartapps.cn/pages/blog/index?blogId=113991947&_swebfr=1&_swebFromHost=baiduboxapp

关于 TCP/IP,必知必会的十个问题