为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的 请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直 等待client发来数据。这样,server的很多资源就白白浪费掉了。
为什么不能用两次握手进行连接? 假定C给S发送一个连接请求分组,S收到了这个分组,并发送了确认应答分组。依照两次握手的协定,S觉得连 接已经成功地建立了,能够開始发送数据分组。但是,C在S的应答分组在传输中被丢失的情况下,将不知道S是 否已准备好。不知道S建立什么样的序列号。C甚至怀疑S是否收到自己的连接请求分组。在这样的情况下,C觉 得连接还未建立成功,将忽略S发来的不论什么数据分组,仅仅等待连接确认应答分组。而S在发出的分组超时 后,反复发送相同的分组。这样就形成了死锁。
这是由于服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后。它能够把ACK和SYN(ACK起应答作 用。而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它只表示对方 没有数据发送给你了。但未必你所有的数据都所有发送给对方了。所以你能够未必会立即会关闭SOCKET,也即你 可能还须要发送一些数据给对方之后,再发送FIN报文给对方来表示你允许如今能够关闭连接了。所以它这里的 ACK报文和FIN报文多数情况下都是分开发送的。
为什么TIME_WAIT状态还须要等2MSL后才返回到CLOSED状态?保证A发送的最后一个ACK报文可以到达B。
MSL即Maximum Segment Lifetime,也就是报文最大生存时间。网络是不可靠的,你无法保证你最后发送的 ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会由于超时未收到ACK报文,而重发FIN+ACK报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。
防止已失效的连接请求报文段出现在本连接中 A在发送完最后一个ACK报文后,再经过2MSL,可以使本连接持续的时间内所产生的所有报文都从网络中消失,可以使下一个连接中不会出现这种旧的连接请求报文段。
DoS攻击、DDoS攻击和DRDoS攻击这三种方法都是利用TCP三次握手的漏洞进行攻击的。 一些防御方法: 1.确保server的系统文件是最新的版本号。并及时更新系统补丁。 2.关闭不必要的服务。 3.限制同一时候打开的SYN半连接数目。 4.缩短SYN半连接的time out 时间。 5.正确设置防火墙 6.禁止对主机的非开放服务的訪问 7.限制特定IP地址的訪问 8.启用防火墙的防DDoS的属性 9.严格限制对外开放的server的向外訪问 10.执行port映射程序祸port扫描程序,要认真检查特权port和非特权port。 11.认真检查网络设备和主机/server系统的日志。仅仅要日志出现漏洞或是时间变更,那这台机器就可能遭到了 攻击。 12.限制在防火墙外与网络文件共享。
为什么TCP不适用于实时传输? TCP影响实时性不是因为握手消耗时间。握手一开始建立完就没事了。
一般来说,单位时间内传输的数据流量比较平滑。 TCP依赖滑动窗口进行流量控制,滑动窗口大小是自适应的,影响滑动窗口主要有两个因素,一是网络延时,二是传输速率,滑动窗口的大小与延时成正比,与传输 速率也成正比。在给定的网络环境下,延时可以认为是固定的,因此滑动窗口仅与传输速率有关,当传输实时数据时,因为数据流通量比较固定,所以这时TCP上的滑动窗口会处于一个不大不小的固定值,这个值大小恰好保证当前生产的数据实时传输到对方,当出现网络丢包时,按TCP协议(快速恢复),滑动窗口将减少到原来的一半,因此速率立刻减半,此时发送速率将小于数据生产速率,一些数据将滞留在发送端,然后滑动窗口将不断增大,直到积累的数据全部发送完毕。上述过程即为典型的TCP流量抖动过程,对于实时传输影响很大,可能形成较大的突发时延,从用户感观角度来说,就是有时比较流畅,但有时卡(“抖一下”,并且比较严重),因此实时传输通常不使用TCP。
自动重传请求ARQ(Automatic Repeat Request):A在超时计时器到期后自动重传数据包,B在收到重传的分 组后丢弃重复分组并向A发送确认。
连续ARQ协议:发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置。
接收方采用累积确认,在收到几个分组后,对按序到达的最后一个分组发送确认。
连续ARQ负面影响:回退N步,需要再退回来重传已发送过的N个分组。
以字节为单位的滑动窗口
超时重传时间略大于平均往返时间。
选择确认SACK(Selective ACK):
建立TCP连接时,在首部选项中加上”允许SACK“的选项,选项中填写每个字节块的边界信息。然而大多数的实现还是重传所有未被确认的数据块。
利用滑动窗口实现流量控制: 为了解决互相等待的死锁问题,TCP为每个连接设置一个持续计数器,若一方收到对方的零窗口通知,就启动持续计数器,若计数器到期,就发送一个仅包含1字节数据的零窗口探测报文段,对方就可以在确认这个探测报文段时给出现在的窗口值,若还为0,就重新设置持续计数器。
拥塞控制指防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。 拥塞控制是一个全局性的过程,涉及到所有的主机,所有的路由器。相反,流量控制往往指点对点通信量的控制,是个端到端的问题。
慢启动
发送方的最大报文段(Sender Maximum Segment Size,SMSS)
初始拥塞窗口cwnd设为不超过2-4个SMSS的数值。
每收到一个对新的报文段的确认后,可以把拥塞窗口增加最多一个SMSS的数值。
每经过一个传输轮次,拥塞窗口cwnd就加倍。
拥塞窗口与慢启动阈值关系算法cwnd < ssthresh慢启动算法cwnd > ssthresh停止使用慢启动算法而开始使用拥塞避免算法cwnd = ssthresh即可使用慢启动算法,也可使用拥塞避免算法拥塞避免
每经过一个往返RTT,就把发送方的拥塞窗口增加一个MSS的大小(单位是字节)。
快重传 -》 让发送方尽早知道发生了个别报文段的丢失,避免发送方误以为网络拥塞进入慢启动阶段。
快重传算法要求接受方不要等待自己发送数据时才进行捎带确认,而是要立即发送确认,即使收到了失序的报文段 也要立即发送对已收到的报文段的重复确认。快重传算法规定,发送方只要一连收到三个重复确认,就知道接受方确实没有收到后一个报文段,就立即进行重传。快恢复
发送方知道只是丢失了个别报文段而不是网络拥塞时,执行快恢复算法。
发送方调整拥塞窗口阈值为ssthresh = cwnd / 2, 同时设置发送窗口cwnd = ssthresh,并开始执行拥塞避免算法。主动队列管理(Active Queue Mangement AQM)
当路由器发生尾部丢弃时,可能会使许多TCP连接在同一时间突然进入到慢启动状态,这称为全局同步。
在网络层,可以使用AQM对路由器中的队列进行智能管理,而不是简单地把尾部的分组丢弃。还没有标准。
一些使用UDP的实时应用,需要对UDP不可靠的传输进行适当改进,以减少数据的丢失。如前向纠错或重传已丢失的报文。
UDP的首部格式UDP数据包检验和:在UDP首部前加上12字节的伪首部。
IP数据报的检验和只校验IP数据报的首部,但UDP的检验和是把首部和数据部分一起都检验。
将UDP伪首部和数据报看做16位的字串接起来的,若不够偶数个字节,填入一个全0字节(但不发送)。然后按二进制反码计算出这些16位字的和,并将结果写入检验和字段。
udp如何实现可靠性传输在应用层实现确认机制、重传机制、窗口确认机制。 目前有如下开源程序利用udp实现了可靠的数据传输。分别为RUDP、RTP、UDT。
基于UDP的数据传输协议(UDP-based Data Transfer Protocol,简称UDT)是一种互联网数据传输协议。UDT的主要目的是支持高速广域网上的海量数据传输,而互联网上的标准数据传输协议TCP在高带宽长距离网络上性能很差。 顾名思义,UDT建于UDP之上,并引入新的拥塞控制和数据可靠性控制机制。UDT是面向连接的双向的应用层协议。
传输层有一个很重要的功能-复用和分用。
复用:指发送方不同的应用进程都可以使用同一个传输层协议传送数据,而分用是指接收方的传输层在剥去报文的首部后能够把数据正确交付到应用进程。
应用层所有的应用进程都可以通过传输层再传送到网络层,这就是复用。
传输层从网络层收到发送给各应用进程的数据后,必须分别交付指明的各应用进程,这就是分用。
应用程序写入数据的字节大小大于套接字发送缓冲区的大小 进行MSS大小的TCP分段。MSS是最大报文段长度的缩写。MSS是TCP报文段中的数据字段的最大长度。数据字段加上TCP首部才等于整个的TCP报文段。所以MSS并不是TCP报文段的最大长度,而是:MSS=TCP报文段长度-TCP首部长度 以太网的payload大于MTU进行IP分片。MTU指:一种通信协议的某一层上面所能通过的最大数据包大小。如果IP层有一个数据包要传,而且数据的长度比链路层的MTU大,那么IP层就会进行分片,把数据包分成托干片,让每一片都不超过MTU。注意,IP分片可以发生在原始发送端主机上,也可以发生在中间路由器上。
TCP粘包和拆包的解决策略消息定长。例如100字节。 在包尾部增加回车或者空格符等特殊字符进行分割,典型的如FTP协议 将消息分为消息头和消息尾。 其它复杂的协议,如RTMP协议等。