在网络传输中,传输控制协议(TCP)是传输层非常重要的一个协议,所以学习TCP协议是很有必要的一件事情。TCP协议是一种可靠的、一对一的、面向有连接的一种通信协议,通常在TCP的网络请求中,在获取到对应的IP地址后,会以随机端口(1024-65535)向服务器80端口发起TCP的连接请求,这个连接会经过TCP/IP协议栈,最后到达服务器。而在建立连接这个过程中,通过一次三次握手来确定连接的建立。
首先,明确一点,因为服务器端维护的只是一个端口,并没有主动建立连接的能力,所以只有客户端能主动的建立与服务器端的连接,所以TCP请求的发起者一定是为客户端。这里先来看一张图。
三次握手
我们知道发起连接的一定是客户端,那来看看三次握手的详细过程。
第一次握手:客户端发送SYN报文到服务器,服务器收到SYN报文之后能确定什么信息呢?信息1->,客户端发送能力是正常,信息2->服务器端明确自己的接收能力是正常。(服务器端明确的信息)
第二次握手:服务器端回应客户端的信息,将收到SYN报文中的seq数据加一,将其作为创建的ACK的数据,再设置一个新的Seq数据,将这个ACK和SYN的报文发送回客户端。在客户端收到SYN和ACK报文之后。会得到的信息为,信息1->服务器端的接收能力正常,信息2->服务器端的发送能力正常,信息3->客户端的接收能力正常。(客户端明确的信息)
第三次握手:客户端回应服务器端的信息,将收到服务器SYN信息中的Seq数据加一,将其作为新的ACK的数据。发送给服务器端,服务器收到ACK信息之后,会确定的信息。信息1->客户端的接收和发送能力正常。信息2->服务器端的接收和发送能力正常。(服务器端明确的信息)
经过三次握手之后,建立起双方之间的连接,三次握手主要的作用是来确定客户端和服务器端的发送和接收能力都正常之后才能建立连接。这里其实会有疑问,一次,两次,四次不可以嘛?根据作用来说,一次和两次肯定是不能完全让客户端和服务器端来明确对方的所有的状态信息。而四次的话,又会造成不必要的资源浪费,所以三次是最简洁明了的,确保两端都获取到对方状态信息。
图片文字只是理论,我们还是需要实际的行动来验证理论,这里来看下使用Wiresshark抓包工具获取到的信息。
在这里呢,使用nc命令在终端来模拟客户端连接服务器,nc -l 6060的为,打开一个6060的端口。nc 127.0.0.1(IP地址)6060(端口)连接6060端口。左边的终端可以视作服务器,右边的终端视作客户端。
在抓包工具中这里可以看到四次?不是三次握手嘛?不要着急,看到第四次的信息是TCP窗口更新,所以这个明确的知道这不是TCP协议中的握手。
这里看到的是三次的握手,这里主要关注的几个点
SYN:报文段,不能携带数据(发起建立报文,会消耗一个序列号)
Seq:全称为sequence number,序列号(第一次随机产生,后续报文中累加)很重要
ACK:报文段,可以携带数据(确认报文,如果携带数据,则会消耗一个序列号,如果不携带数据,则不会消耗序列号seq)
Ack:是ACK的序列号,根据SYN报文中的Seq来生成
第一次握手:[SYN] 为报文段的类型,可以看到在1中的报文中的Seq为2812367146,这是一个随机产生的序列号,每一次的报文都会有自己的序列号作为标识。服务器端接收到这个SYN报文之后,知道的信息为,客户端发送了一个建立连接的SYN包,编号为2812376146。
第二次握手:在2中有两个报文段是[SYN,ACK],SYN报文的序列号seq为一个新随机产生的序列号587195924,而新创建的ACK报文的Ack序列号为2812367147。这里的意思是服务器端发出的意思是为两重,第一个是建立连接的SYN信息,有自己生成的seq。第二个是确认的ACK信息,将第一次握手收到的SYN信息中的Seq+1作为ACK的序列号,告诉客户端,收到了2812376146这个序列号的SYN报文。
第三次握手:在3中只有一个ACK的报文,ACK的Ack序号为587195925。这里的意思是确认了服务器的SYN包,Ack的序号为第二次握手中SYN包中Seq+1,因为这里的ACK报文只是确认,并没有携带数据,所以这里的seq还是第二次握手中ACK的序号。
通过三次握手的连接之后,下一次报文中的Seq序列号为第三次ACK报文中Seq+1
四次挥手
抓包工具的数据也验证了理论,所以接下来我们来看一下断开连接的四次挥手,同样从理论到验证,如下图所示
问题:四次挥手一定是客户端发起嘛?
答案:这是不一定的,因为在TCP的连接中,所以只要有任何一端发起了断开的请求,对方收到响应之后做出断开请求的四次挥手,即完成了断开连接。所以断开连接的四次挥手可以为客户端发起,同样也可以由服务器端发起。
上图中为客户端发起断开连接的步骤,服务器端发起是同样的道理。
第一次挥手:客户端发送一个FIN和ACK的报文,序列号seq为传输数据包中最后一次的Seq+1,ACK的序列号Ack则为上一次ACK包中的序列号。将客户端的状态修改为FIN_WAIT1。服务器收到之后明确信息->客户端在等待关闭。
第二次挥手:服务器将收到FIN报文中的Seq数据+1作为新ACK报文的Ack,将收到的ACK报文中的Ack+1作为新报文ACK的Seq,将服务器端的状态调整为CLOSE_WAIT,然后将新的确认报文ACK发送给客户端。客户端收到之后明确信息->服务器端知晓客户端在等待关闭,同时将客户端的状态调整为FIN_WAIT2。
第三次挥手:服务器再次的发起FIN和ACK的报文,FIN的Seq是最后一次报文的Seq+1,ACK报文的Ack是最后一次ACK报文的的Ack+1,将服务器端的状态修改为LAST_ACK。客户端在收到之后明确信息->服务器端发送了最后一次,在等待关闭。
第四次挥手:客户端发起ACK报文,新的ACK报文的seq为第三次挥手收到的Ack,而Ack为收到FIN中的Seq+1,将自己的状态调整为TIME_WAIT。服务器端收到之后明确信息->客户端关闭,将服务器端的状态调整为CLOSED。而客户端在TIME_WAIT状态等待2MSL秒之后,将自己的状态调整为CLOSED。
同样这里使用抓包工具来验证
这里的数据就不一一解读了,因为在连接之后,没有做任何的数据传输,所以这里的Seq和Ack的序号和连接的时候是连续的。
FIN:报文段,不能携带数据(关闭报文,会消耗一个序列号)
这里说明一下两个点
1:为什么一定要四次挥手,可以看到,在关闭的时候,第二次和第三次挥手都是由被动方(图中为服务器端)发起,因为在某些时候可能传输的报文还没有传输完成,所以先通知客户端收到关闭的请求,然后确认服务器端的传输都完成之后,再发起第三次挥手,告诉客户端要断开连接。
2:为什么在最后一次挥手之后要等待2MSL再调整状态为CLOSED,两个原因,第一,是需要确定已经发出去,因为ACK报文有可能丢失,会需要重发。第二,如果立马关闭的话,有可能在下一次连接的是相同的IP和端口,为了防止旧连接和新连接的数据发生混乱,所以设置等待的时间让旧连接的数据完全关闭,这样就不会让旧连接和新连接之间数据造成混乱。
保障数据包有效
TCP是可靠的数据连接,可是只是通过三次握手和四次挥手就一定能保证数据的传输不会出现问题嘛?当然是不可以,所以TCP通过以下的几个控制来确保数据包的传输有效。
一,校验和
1、首先将检验和置零;
2、然后将TCP伪首部部分,TCP首部部分,数据部分都划分成16位的一个个16进制数
3、将这些数逐个相加,记得溢出的部分加到最低位上,这是循环加法:0xc0a8+ 0x0166+……+0x0402=0x9b49
4、最后将得到的结果取反,则可以得到检验和位0x64b6
发送方:原码相加 ,并将高位叠加到低位,取反 ,得到反码求和结果,放入校验和
接收方:将所有原码 相加,高位叠加, 如全为1,则正确
发送的数据包的二进制相加然后取反,目的是检测数据在传输过程中的任何变化。如果收到报文段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段,这时 TCP 发送数据端超时后会重发数据;
二. 确认应答+序列号
序列号:TCP传输时将每个字节的数据都进行了编号,这就是序列号Seq。
确认应答:TCP传输的过程中,每次接收方收到数据后,都会对传输方进行确认应答,也就是发送ACK报文。这个ACK报文当中带有对应的确认序列号,告诉发送方,接收到了哪些数据,下一次的数据从哪里发。
序列号的作用不仅仅是应答的作用,有了序列号能够将接收到的数据根据序列号排序,并且去掉重复序列号的数据。
应答机制:当 TCP 收到发自 TCP 连接另一端的数据,它将发送一个确认(累积确认:对所有按序接收的数据的确认)。这个确认不是立即发送,通常将推迟几分之一秒
TCP给发送的每一个包进行编号,接收方对数据包进行排序,把有序数据传送给应用层。
三,超时重传
当报文发出后在一定的时间内未收到接收方的确认,发送方就会进行重传(通常是在发出报文段后设定一个闹钟,到点了还没有收到应答则进行重传)
接收方获取到重复的数据之后,利用序列号识别到重复的数据,将其丢弃,再重新发送ack报文
四,流量控制
TCP根据接收端的处理能力,决定发送端的发送速度,TCP通过滑动窗口来进行流量控制
流量窗口:因为TCP是全双工通信,通信的任意一方都会维护另一方的接收窗口(即接收方当前可用的缓存空间),数据是动态变化的,缓存空间也是动态的,也称之为滑动窗口
五,拥塞控制
为了避免由于网络拥堵而采取的对发送方发送速率的限制称为拥塞控制
TCP 通过拥塞窗口实现拥塞避免->TCP 的每一端除了维护进行流量控制的滑动窗口外,还会维护一个拥塞窗口(cwnd),拥塞窗口就是对 TCP 发送方的发送速率进行限制的,具体来说的就是 TCP 会控制发送方发送到连接中的但是还没有被接收方确认的数据量。
通过上述的控制,这样就给数据的传输安全有了一定的保障。