三次握手
- 客户机向服务器发送请求报文段,这个报文段的首部中同步位SYN置1,同时选定一个初始序号seq=x。SYN报文段不能携带数据,但要消耗一个序号。这一步过后TCP客户进程进入SYN-SENT(同步已发送)状态。SYN=1,seq=x
- 服务器的TCP收到连接请求报文段后,如果同意建立链接,则向客户机发回确认,并为该TCP连接分配缓存和变量、在确认报文段中,把SYN和ACK都置1.确认报文段不能携带数据,但也要消耗一个序号。这一步过后TCP服务器进程进入SYN-RCVD(同步收到)状态。SYN=1,ACK=1,seq=y,ack=x+1
- 客户机收到确认报文段后,要向服务器给出确认,并未TCP连接分配缓存和变量。确认报文段的ACK置1.该报文段可以携带数据,若不携带数据则不消耗序号。这一步过后TCP客户进程进入ESTABLISHED(已建立连接)状态。ACK=1,seq=x+1,ack=y+1
为什么不用“两次握手”
这主要是为了防止两次握手情况下已失效的连接请求报文段突然又传送到服务器而产生错误。
例如:A向B发送TCP连接请求,第一个连接请求报文在网络的某个结点长时间滞留,A超时后认为报文丢失,于是再重传一次连接请求,B收到后建立连接。数据传送完毕后双方断开连接。而此时,前一个滞留在网络中的连接请求到达B,而B认为A又发来了连接请求。此时若使用“三次握手”,则B向A返回确认报文段,由于是一个失效的连接请求,A不予理睬,建立连接失败。若采用的是“两次握手”,则这种情况下B认为传输连接已建立,并一直等待A传输数据,而A此时并无连接请求,因此不予理睬,这样就造成了B的资源白白浪费。
SYN泛洪攻击
SYN泛洪攻击利用TCP三次握手协议的缺陷,向目标主机发送大量的伪造源地址的SYN连接请求,使得被攻击方资源耗尽,从而不能够为正常用户提供服务。
在TCP协议三次握手的连接过程中,如果一个用户向服务器发送了SYN报文,服务器又发出 SYN+ACK 应答报文后未收到客户端的 ACK 报文,这种情况下服务器端会再次发送SYN+ACK给客户端,并等待一段时间后丢弃这个未完成的连接,这段时间的长度称为SYN Timeout,一般来说这个时间是分钟的数量级。
SYN 泛洪攻击所做的就是利用这个SYN Timeout和TCP/IP协议族中的另一个漏洞: 报文传输过程中对报文的源 IP 地址完全信任进行攻击。SYN 泛洪攻击通过发送大量的伪造 TCP 连接报文而造成大量的 TCP 半连接,服务器端将为了维护这样一个庞大的半连接列表而消耗非常多的资源。这样服务器端将忙于处理攻击者伪造的TCP连接请求而无法处理正常连接请求,甚至会导致堆栈的溢出崩溃。
造成SYN泛洪攻击最主要的原因是TCP/IP协议的脆弱性。TCP/IP是一个开放的协议平台,它将越来越多的网络连接在一起,它基于的对象是可信用户群,所以缺少一些必要的安全机制,带来很大的安全威胁。例如常见的IP欺骗、TCP连接的建立、ICMP数据包的发送都存在巨大的安全隐患,给SYN泛洪攻击带来可乘之机。
SYN攻击防御
最常用的一个手段就是优化主机系统设置。比如降低SYN timeout时间,使得主机尽快释放半连接的占用或者采用SYN cookie设置,如果短时间内收到了某个IP的重复SYN请求,我们就认为受到了攻击。我们合理的采用防火墙设置等外部网络也可以进行拦截。
四次挥手
- 客户端向服务器发送连接释放报文段,该报文段的终止位FIN置1,FIN报文段即使不携带数据,也消耗一个序号。这一步后客户端进入FIN-WAIT-1(终止等待1)状态。FIN=1,seq=u
- 服务器收到连接释放报文段后即发出确认,然后服务器进入CLOSE-WAIT(关闭等待)状态。ACK=1,seq=v,ack=u+1
- 服务器发出FIN=1的连接释放报文段。这一步过后服务器进入LAST-ACK(连接关闭)状态。FIN=1,ACK=1,seq=w,ack=u+1
- 客户端收到连接释放报文段后,必须发出确认,把确认报文段中的确认位ACK置1。此时TCP连接还未释放,必须经过时间等待计时器设置的2MSL(最长报文段寿命)后,客户机才进入CLOSED(连接关闭)状态。ACK=1,seq=u+1,ack=w+1
为什么要等待2MSL
- 保证A发送的最后一个确认报文段能够到达B。如果A不等待2MSL,若A返回的最后确认报文段丢失,则B不能进入正常关闭状态,而A此时已经关闭,也不可能再重传。
- 防止出现“已失效的连接请求报文段”。A在发送最后一个确认报文段后,再经过2MSL可保证本连接持续的时间内所产生的所有报文段从网络中消失。
为什么握手三次而挥手是四次
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,”你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步挥手。
TCP粘包
TCP粘包就是指发送方发送的若干包数据到达接收方时粘成了一包,从接收缓冲区来看,后一包数据的头紧接着前一包数据的尾,出现粘包的原因是多方面的,可能是来自发送方,也可能是来自接收方。
原因
- 发送方原因
TCP默认使用Nagle算法(主要作用:减少网络中报文段的数量),而Nagle算法主要做两件事:
- 只有上一个分组得到确认,才会发送下一个分组
- 收集多个小分组,在一个确认到来时一起发送
Nagle算法造成了发送方可能会出现粘包问题
- 接收方原因
TCP接收到数据包时,并不会马上交到应用层进行处理,或者说应用层并不会立即处理。实际上,TCP将接收到的数据包保存在接收缓存里,然后应用程序主动从缓存读取收到的分组。这样一来,如果TCP接收数据包到缓存的速度大于应用程序从缓存中读取数据包的速度,多个包就会被缓存,应用程序就有可能读取到多个首尾相接粘到一起的包。
如何处理
- 发送方
对于发送方造成的粘包问题,可以通过关闭Nagle算法来解决,使用TCP_NODELAY选项来关闭算法。
- 接收方
接收方没有办法来处理粘包现象,只能将问题交给应用层来处理。
- 应用层
格式化数据:每条数据有固定的格式(开始符,结束符),这种方法简单易行,但是选择开始符和结束符时一定要确保每条数据的内部不包含开始符和结束符。
发送长度:发送每条数据时,将数据的长度一并发送,例如规定数据的前4位是数据的长度,应用层在处理时可以根据长度来判断每个分组的开始和结束位置。
UDP会粘包吗
TCP采用了基于流的传输,基于流的传输不认为消息是一条一条的,是无保护消息边界的
保护消息边界:指传输协议把数据当做一条独立的消息在网上传输,接收端一次只能接受一条独立的消息
UDP则是面向消息传输的,是有保护消息边界的,接收方一次只接受一条独立的信息,所以不存在粘包问题。
举个例子:有三个数据包,大小分别为2k、4k、6k,如果采用UDP发送的话,不管接受方的接收缓存有多大,我们必须要进行至少三次以上的发送才能把数据包发送完,但是使用TCP协议发送的话,我们只需要接受方的接收缓存有12k的大小,就可以一次把这3个数据包全部发送完毕。
TCP可靠传输
TCP使用校验、序号、确认和重传等机制达到可靠传输地目的。
- 序号
TCP首部的序号字段用来保证数据能有序提交给应用层,TCP把数据视为一个无结构但有序的字节流。序号建立在传送的字节流上,而不建立在报文段上。
TCP连接传送的数据流中的每个字节都编上一个序号。序号字段的值是指本报文段所发送的数据的第一个字节的序号。
- 确认
TCP首部的确认号是期望收到对方的下一个报文段的数据的第一个字节的序号。发送方缓存区会继续存储那些已发送但未收到确认的报文段,以便在需要的时候重传。
TCP默认使用累计确认,即TCP只确认数据流中到第一个丢失字节为止的字节,
- 重传
- 超时
TCP每发送一个报文段,就对这个报文段设置一次计时器。计时器设置的重传时间到期但还未收到确认,就要重传这一报文段。
- 冗余ACK(冗余确认)
超时触发重传存在的一个问题是超时周期往往太长。
发送方通常可在超时事件发生之前通过注意所谓的冗余ACK来较好地检测丢包情况。
冗余ACK就是再次确认某个报文段的ACK,而发送方先前已经收到过该报文段的确认。
TCP规定当发送方收到对同一个报文段的3个冗余ACK时,就可以认为跟在这个确认报文段之后的报文段已经丢失。
TCP拥塞控制
拥塞控制是指防止过多的数据注入网络,保证网络中的路由器或者链路不至于过载。出现拥塞时,断点并不了解拥塞发生的细节,对通信连接的端点来说,拥塞往往表现为通信时延的增加
拥塞控制和流量控制的区别
拥塞控制是让网络能够承受现有的网络负荷,是一个全局性的过程,涉及所有主机、所有的路由器,以及与降低网络传输性能有关的所有因素。
流量控制往往是指点对点的通信量的控制,是一个端到端的问题。它要做的是控制发送方发送数据的速率,以便接收端来得及接收。
四种算法
- 慢开始
TCP开始发送报文段时先设置拥塞窗口=1,使得发送方在开始时只发送一个报文段(目的是试探一下网络的拥塞情况),然后再逐渐增大拥塞窗口。
每经过一个传输轮次(往返时延RTT),拥塞窗口就会加倍,即拥塞窗口大小指数式增长。慢开始一直把拥塞窗口增大到一个规定的慢开始门限,然后改用拥塞避免算法
- 拥塞避免
每经过一个往返时延RTT就把发送方的拥塞窗口加1,而不是加倍,使拥塞窗口按线性规律缓慢增长。
- 快重传
快重传技术使用了冗余ACK来检测丢包的发生,同样,冗余ACK也用于网络拥塞的检测。快重传并非取消重传计时器,而是在某些情况下可更早地重传丢失的报文段。
当发送方连续收到三个重复的ACK报文时,直接重传对方尚未收到的报文段,而不必等待那个报文段设置的重传计时器超时。
- 快恢复
当发送方连续收到三个冗余ACK时,执行“乘法减小”算法,把慢开始门限设置为此时发送方拥塞窗口的一半。与慢开始不同之处是它把拥塞窗口的值设置为慢开始门限改变后的数值,然后执行拥塞避免算法(“加法增大”),使得拥塞窗口缓慢地线性增大。
使用时机
- TCP连接建立和网络出现超时时,采用慢开始和拥塞避免算法
- 当发送方接收到冗余ACK时,采用快重传和快恢复算法