多次会看TCP的三次握手四次挥手,感觉理解的都很表面,最近参考了其他博主的博文,做了下总结方便理解,如有哪里理解错误,欢迎指出:
TCP首部参考图 :
一、一些基本概念,帮助理解,已了解可向后看:
首先我们知道tcp是传输控制协议,它属于传输层协议, 用于提供port到port面向连接的可靠的字节流传输。是建立在物理层、数据链路层、网络层之上的协议,而底层的网络是不可靠的,可能路由出现问题、网关出现问题、网线出现问题,这些问题我们是没办法保证的,主机A没办法保证自己发送出来的消息主机B一定可以收到,所以tcp建立了一种反馈机制,做出的行为要得到反馈,即ACK,相对的保证了在不可靠的网络层构建中建立了可靠地传输层;
tcp中的六个标志位:
字段 | 含义 |
URG | 紧急指针是否有效,为1,表示某一位需要被优先处理 |
ACK | 确认号是否有效 为1,有效 |
SYN | 请求建立连接,并在其序列号的字段进行序列号的初始值设定,建立连接 设为1 |
FIN | 释放连接 |
PSH | 提示接收端应用程序立即从TCP缓冲区把数据读走 |
RST | 重新建立连接 |
序列号seq:用来标记数据段的顺序,
确认号ack:期待收到对方下一个报文段的序号,一般是当前报文段的最后一个字节的编号+1即为确认号
二、三次握手:
第一次握手:主机A向主机B发送一个SYN有效同步信息,同时随机生成seq=x,此时主机A进入SYN-SENT同步发送状态,等待服务器确认,(SYN=1,seq=x)
第二次握手:主机B收到主机A发送的SYN信息,会回送主机A一个ACK确认有效信息(ack=x+1,ACK=1),同时发送自己的SYN同步信息,随机seq=y,即发送ACK+SYN信息给主机A,此时主机B进入SYN-RCVD同步收到状态;
第三次握手:主机A收到主机B发送的信息包,确认信息无误后,回送给主机BACK确认有效信息即(seq=x+1,ack=y+1)
为什么是三次握手而不是两次握手?
其实TCP采用三次握手的原因很简单:
1、为了实现可靠地数据传输,TCP协议的通信双方,都必须维护一个序列号,标识自己发送出去的数据包中,那些事已经被对方收到的。三次握手的过程即是通信双方相互告知序列号起始值,并确认对方已经收到了序列号起始值的必经之路,
2、如果是两次握手,至多只有连接的发起方的起始值序列号能被确认,另一方的序列号得不到确认
例子(可选看):
如果是两次连接,主机A发送SYN确认信息给主机B,主机B收到SYN信息后回送ACK确认信息,此时主机B是认为建立连接成功,可以发送数据。在主机B回送的确认信息丢失的情况下,主机A是认为建立不成功的,会忽略主机B发送的数据信息,只会等待确认信息,此时,主机B发送数据得不到回复就会形成死锁的情况;
四次挥手
由于TCP连接是全双工的,因此,每个方向都必须要单独进行关闭,当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,
第一次挥手:主机A向主机B发送FIN释放信息,表示数据发送完毕,请求关闭主机A到主机B的数据传送,主机A进入 FIN_WAIT_1状态;
第二次挥手:主机B收到主机A的FIN请求,发送给主机A一个ACK确认信息,主机B进入CLOSE_WAIT状态;
此时不能同时向主机A发送FIN释放请求,需要等待数据发送完后在发送FIN
第三次挥手:主机B向主机A发送FIN释放请求,用来关闭主机B向主机A的数据传输,主机B进入LAST_ACK状态;
第四次挥手:主机A收到主机B的FIN请求,回送给主机BACK确认信息,四次挥手完毕
三、TCP特点:
全双工链接
该链接的两端有两条彼此独立、方向相反的传输通道,连接双方都需要建立TCP连接
面向连接
通信双方在开始传输数据前,必须通过“三次握手”的方式建立一条逻辑上的链路,用于传输数据
可靠协议
TCP协议借助于序列号和确认号,可以再数据包丢失的情况下进行重传,而通过确认号可以确定数据包是否没有收到是否是被重传的,依靠这些保证数据的可靠性
面向字节流
TCP协议会将数据包切分切分为很多小的数据包,并封装为ip包进行发送,被切分的数据包序列号不断变化,并不会按顺序到达, 根据接收方根据序列号和确认号进行重组
为什么连接的时候是三次握手,关闭的时候却是四次握手?
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。
如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75分钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。