什么是TCP?
传输控制协议(TCP,Transmission Control Protocol)是面向连接的、可靠的、基于字节流的传输层通信协议
TCP的特性
- TCP 提供一种面向连接的、可靠的字节流服务
- 在一个TCP连接中,就有两方进行彼此通信,广播和多播不能用于TCP
- TCP 使用校验和,确认和重传机制来保证可靠传输
- TCP 给数据分节进行排序,并使用累积确认保证数据的顺序不变和非重复
- TCP 使用滑动窗口机制来实现流量控制,通过动态改变窗口的大小进行拥塞控制
- 注意:TCP 并不能保证数据一定会被对方接收到,因为这是不可能的。TCP 能够做到的是,如果有可能,就把数据递送到接收方,否则就(通过放弃重传并且中断连接这一手段)通知用户。因此准确说 TCP 也不是 100% 可靠的协议,它所能提供的是数据的可靠递送或故障的可靠通知。
三次握手
三次握手(Three-way Handshake)其实就是建立一个TCP连接时,需要客户端和服务端总共发送3个包。
三次握手的目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认好,交换TCP窗口大小信息
在socket编程中,客户端中执行connet()时。将触发三次握手。
进行三次握手:
第一次握手 (SYN=1 , seq=x):
客户端给服务端发送一个SYN报文,并指明客户端的初始化序列号ISN。
发送完毕,此时客户端处于SYN_SENT状态。
第二次握手 (SYN=1 , ACK=1 , seq=y , ACKnum=x+1):
服务端发回确认包(ACK)应答。即SYN标志位和ACK标志位均为1。服务端选择自己ISN序列号,放到Seq域里,同时将确认序号(Acknowledgement Number)设置为客户的ISN+1,即X+1。
发送完毕,此时客户端进入SYN_RCVD状态。
第三次握手 (ACK=1 , ACKnum=y+1):
客户端再次发送确认包(ACK) ,SYN标志位为0,ACK标志位为1,并且把服务端发来ACK的序号字段+1,放在确定字段中发送给对方,并且在数据段放写ISN的+1
发送完毕,客户端进入ESTABLISHED状态,当服务器收到这个包时,也进入ESTABLISHED状态
至此,TCP三次握手结束。
例子
小明:你好~ 能听到我说话吗?
小蒋:你好~ 我能听到~ 你能听到我说话吗?
小明:我也能听到你说话!
小明、小蒋 开始通话
为什么需要三次握手,两次不可以吗?
三次握手的目的
第一次握手:客户端发送网络包 --> 服务端收到
这样服务端就能得出结论:客户端的发送能力,服务端的接收能力时正常的。
第二次握手:服务端发送网络包 --> 客户端收到
这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力均为正常。
但是此时服务端并不能确认客户端的接受能力是否正常。
第三次握手:客户端发送网络包 --> 服务端收到
这样服务端就能得出结论:客户端的接收、发送能力,服务端自身的接收、发送能力正常。
因此,需要三次握手才能确认双方的接收与发送能力是否正常。
如果为两次握手
第一次握手
客户端发送网络包 --> 因连接请求报文丢失而未收到确认 --x-- 服务端未收到
第二次握手
客户端再一次发送网络包 --> 服务端收到
数据传输完毕后,释放连接。
客户端共发出了两个连接请求报文段,第一个丢失,第二个到达了服务端,但是第一个丢失的报文段只是在某些网络节点长时间滞留,延误到连接释放以后的某个时间点到达服务端,
此时服务端误以为客户端再一次发送了新的连接请求,于是向客户端发出确认报文段,同意建立连接,但是此时没有采用三次握手,所以只要服务端发出确认,就直接建立起新的连接。
此时等同客户端忽略服务端发来的确认,也不发送数据,导致服务端一直等待客户端发送数据,浪费资源
SYN攻击
SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则不断回复确认包,并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。
SYN 攻击是一种典型的 DoS/DDoS 攻击。
检测SYN攻击很简单,当你发现你的服务器中突然出现了大量的半连接状态,并且源地址都为随机时,基本就可以断定受到了SYN攻击。
常见的防御 SYN 攻击的方法有:
- 缩短超时(SYN Timeout)时间
- 增加最大半连接数
- 过滤网关防护
- SYN cookies技术
理论上SYN攻击无法被彻底阻止,除非重新设计TCP协议
ISN是固定的吗?
当一端为建立连接而发送它的SYN时,它为连接选择一个初始序号。
ISN随时间而变化,因此每个连接都将具有不同的ISN。
ISN可以看作是一个32比特的计数器,每4ms加1 。这样选择序号的目的在于防止在网络中被延迟的分组在以后又被传送,而导致某个连接的一方对它做错误的解释。
三次握手的其中一个重要功能是客户端和服务端交换 ISN,以便让对方知道接下来接收数据的时候如何按序列号组装数据。
如果 ISN 是固定的,攻击者很容易猜出后续的确认号,因此 ISN 是动态生成的
四次挥手
TCP连接的拆除需要发送四个包,因此被称为四次挥手(Four-way handshake)。客户端和服务端均可主动发起挥手操作。
socket编程中,任何一方执行close(),即可开始挥手操作
进行四次挥手:
第一次挥手(FIN=1,seq=x)
客户端想要关闭连接,向服务端发送FIN值为1的包。表示自己已经没有数据可以发送,但是仍然可以接收数据。
此时客户端进入 FIN_WAIT_1状态
第二次挥手(ACK=1,ACKnum=x+1)
服务端确认客户端发来的数据包,向客户端发送一个确认包,表示自己确认了客户端发起的关闭连接的请求,但是还没有做好关闭连接的准备。
发送完毕后,服务端进入CLOSE_WAIT状态,客户端收到确认包后进入FIN_WAIT_2状态,等待服务端关闭连接
第三次挥手(FIN=1,seq=y)
服务端准备好关闭连接后,向客户端发起关闭连接请求,FIN值为1
发送完毕后,服务端进入LAST_ACK状态,等待来自客户端的最后一个ACK包
第四次挥手(ACK=1,ACKnum=y+1)
客户端接收到来自服务端的关闭连接请求包,向服务端发送确认包
服务端接收到客户端的确认包后,关闭连接,进入CLOSED状态。客户端则进入TIME_WAIT状态等待可能出现的要求重传的ACK包
客户端在等待了2MSL(2 Maximum Segment Lifetime,两个最大段生命周期)之后,没有收到来自服务端的ACK包,认为服务端已经正常关闭连接,所以自己也关闭连接,进入到CLOSED状态。
至此,TCP四次挥手结束
例子(懒得画图,通俗易懂的对话形式)
小渣:腻了,我们分手吧!把我给你买的东西全都还给我
小绿:臭渣男,祝你万箭穿心!(开始打包小渣买给自己的东西)
小绿:还你!臭渣男(拉黑小渣)
小渣:借你吉言~ 以后不要再联系了~ 我值得更好的~
(小渣,等了一会确定没有了小绿的回复,拉黑小绿)
至此 小绿,小渣 断开连接
为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSED状态?
讲道理,四个报文都发送完毕,我们应该可以直接进入CLOSED状态了,但是我们必须假设不可靠的。如果客户端发送出最后的ACK回复,服务器没有收到,服务器将不断重复发送FIN报文。所以客户端不能立即关闭,它必须确认服务器端接收到了该ACK。
客户端会在发送出ACK之后进入到TIME_WAIT状态,同时设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么客户端会重发ACK并再次等待2MSL。
所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,客户端都没有再次收到FIN,那么客户端推断ACK已经被成功接收,则结束TCP连接。