目录
Tcp特点主要是分为四点:有连接,可靠传输,面向字节流,全双工。
这里我们主要介绍可靠传输
确认应答(ACK)
确认应答是保证"可靠性"的最核心的机制。
接收方反馈一个应答报文(ACK),表示已经收到。
假设现在A想去B家里玩,于是A给B发消息,正确的顺序是:
但是网络传输比较复杂,可能会出现一种情况"先发后至",由于数据的长度不同或者传输网络不同,先发的数据不一定先到达,接收方的数据可能是乱序的:
当B回复A的时候若存在对应的关系,那么即使出现"后发先至"的问题也会顺利的解答:
上述方法,虽然可以解答出A的问题,但是额外信息比较多,比较占带宽,并且不能解决"活法先致"的问题。
所以我们就有一个新的解决方法:针对数据编号。
但是真实的TCP并不是按照上述情况进行编号的,由于TCP是面向字节流的,此处的编号并不是按照一条,两条进行编号的,而是按照字节来编号的。
确认应答是一种特殊的报文(ACK),所谓的应答报文,本质上就是字段为1的报文,此时报头中的"确认序号"字段才是生效的。
如果发送多个数据,每个数据都会带有一个序号,接收方收到数据之后,就知道数据所带的序号,根据序号给出的确认序号(告诉发送方下次给我发的序号),发送给发送方,发送方就知道接收方收到哪些数据。
确认序号=开始序号+数据长度(字节)- 1
超时重传
确认应答是一种理想的情况,但是数据在开发的过程中就会出现丢包的情况
以上面的例子为例,当A给B发消息,你在家呢?但是等了好久,A还是没有收到B的回复消息,此时,就会出现三种情况:
- B不想会A的消息
- B没有收到A的消息(丢包情况1:发送请求丢失)
- B回复了A的消息,但是A没有收到(丢包情况2:应答的ACK丢失)
2、3情况:丢包的两种情况,对于发送方来说无法确定是哪种情况,因此,进行统一处理:当发送一条数据之后,TCP内部就会自动启动一个定时器,达到一定时间没有收到ACK,定时器就会自动触发重传消息的动作------超时重传
如果在数据重传的时候,又会出现一次丢包,这个时候的等待的时间就会比上一次短。
上述丢包的两种情况:
一种是请求丢失:重传没有问题
一种是ACK丢失:重传就意味着接收方收到了相同数据,TCP会在内部进行数据去重,保证应用层读到的数据不是重复数据
建立连接-三次握手
当A给B打电话的时候,打电话的时候同样要验证自己一起对方的话筒和自己的听筒是否正常
第一次握手: 刚开始,A 不知道自己和 B 手机的听筒和话筒是否正常,所以 A说"喂,你能听到吗?"
第二次握手: B 听到后,说明 A 的话筒和 B 的听筒正常,但 B 还需进一步检查自己的话筒和 A 的听筒是否正常;同时 B 把 A 话筒正常和自己听筒正常的消息传递给 A;于是 B "我能听到,你呢?"
第三次握手: A 收到 B 的消息后,就证明了 A 听筒正常,B 话筒正常
以上三次握手就保证A、B的听筒和话筒都是正常,也就保证了通话的正常,这就也是类似网络建立连接的三次握手
TCP中真实的建立连接过程:
**第一次握手:**客户端希望与服务器建立连接,因此它首先向服务器发送一个TCP报文段,其中包含SYN(同步)标志位。这个SYN标志位表示客户端希望建立连接,并在报文段中包含一个初始序列号(ISN),该序列号用于标识客户端发送的数据。
**第二次握手:**服务器收到客户端的SYN后,会确认客户端的请求。服务器向客户端发送一个TCP报文段,其中包含SYN和ACK(确认)标志位。服务器也会选择自己的初始序列号(ISN)。这个ACK用于确认客户端的SYN,并表示服务器已经准备好建立连接。
**第三次握手:**客户端收到服务器的SYN-ACK后,会发送一个带有ACK标志位的TCP报文段给服务器。这个ACK用于确认服务器的SYN,并表示客户端也已经准备好建立连接。同时,客户端也会发送自己的初始序列号。
建立连接的过程,相当于通信双方各自给对方发送 SYN,在各自给对方发送给 ACK,只不过中间的 ACK 和 SYN 合二为一了,于是最后就是"三次握手"。
断开连接-四次挥手
**三次握手:**双方各自向对方发起建立连接的请求,确保双方都明确知道对已准备好连接。
**四次挥手:**用于确保双方在终止连接之前完成数据传输,并且都明确知道对方已经准备好关闭连接。
以打电话为例子:
TCP中真实的断开连接过程:
第一次挥手(客户端向服务器发送FIN)
- 客户端决定关闭连接,因此向服务器发送一个TCP报文段,其中包含FIN(Finish)标志位。则合格FIN表示客户端已经完成数据发送,并请求关闭。客户端进入FIN_WAIT状态。
第二次挥手(服务器回复ACK):
- 服务器收到客户端的FIN后,会发送一个确认ACK数据报作为响应,以确认它已经收到客户端的关闭请求,同时,服务器进入CLOSE_WAIT状态。
第三次挥手(服务器向客户端发送FIN):
- 当服务器也决定关闭连接时,它会向客户端发送一个带有FIN标志位的TCP报文段,表示服务器已经完成数据发送并请求关闭连接。服务器1进入LAST_ACK状态。
第四次挥手(客户端回复ACK):
- 客户端收到服务器的FIN后,会回复一个确认ACK,表示客户端已收到服务器的关闭请求,此时客户端进入TIME_WAIT状态,等待一段时间(通常是两倍的最大寿命,以确保服务器收到ACK),然后才最终关闭连接。
在客户端的TIME_WAIT状态结束后,连接关闭。服务器在发送FIN后等待一段时间,确认客户端收到FIN的ACK之后,连接终止。
四次挥手三次挥完不行呢?
通常是不可以的,即:上述2、3为什么没有合并在一起?
因为中间两次操作时机不一样,ACK是收到FIN之后立即由操作系统内核返回的数据报,告诉客户端收到了关闭的消息,而FIN是应用程序处理完接受缓冲区的数据之后,调用close方法触发的。
但是若出发了延时应答机制,就可以三次挥完。