TCP概述
- TCP是
面向连接
的传输层协议 每一条TCP连接只能有两个端点,每一条只能是点对点的 *
TCP提供可靠交付的服务`,通过TCP连接传送的数据,无差错,无丢失,不重复并且按序到达。TCP提供全双工通信
,TCP允许通信双方的应用进程在任何时候都发送数据。TCP连接的两端都有发送缓存和接受缓存,用来临时存放双方通信的数据。在发送时,应用程序在把数据发送给TCP缓存后,就可以做自己的事,而TCP在何时的时候把数据发送出去。在接收时,TCP把收到的数据放入缓存,上层应用进程在合适的时候读取缓存中的数据- 面向字节流:TCP并不关心应用进程一次把多长的报文发送到TCP缓存中,而是根据双方给出的窗口值和当前网络拥塞程度来决定一个报文段应该包含多少字节
传输文件面向字节流示意
TCP首部格式
源端口和目标端口
:分别写入源端口号和目标端口号序号
:占4个字节,在一个TCP
连接中传送的字节流中的每一个字节都按顺序编号
,整个要传送的字节流的起始序号必须在连接建立时设置。首部中的序号字段值则指的是报文段所发送的数据的第一个字节的序号这个序号初始化时必须是随机
的:因为若固定的话,当一个客户端发送一个数据报文之后关闭连接若这个报文没有及时到达服务端,之后这个客户端再次建立连接,此时之前的报文到达,造成干扰;另外可以模拟客户端对服务端进行攻击。确认号
:期望收到下一个报文段的第一个数据字节的序号数据偏移
:它指出TCP报文段的数据开始处距离TCP报文段的起始处有多远
,这个字段实际上指出TCP
报文段的首部长度,由于首部中海油长度不确定的选项字段,因此数据偏移字段是有必要的
下面6个控制位说明本报文段的性质
URG
:在发送端进行紧急发送;当URG=1时,表明紧急指针字段有效,它告诉系统此报文段中有紧急数据,应尽快传动(相当于高优先级的数据),而不是按原先的排队顺序来传送。- PSH:在客户端进行紧急接受
- ACL与SYN建立会话时使用,三次握手:
仅当ACK=1时确认号字段才有效。当ACK=0时,确认号无效,TCP规定,在连接建立后所有传送的报文段都必须把ACK设置为1
;- RST:复位重新建立连接
- FiN:释放连接,用来释放可连接,当
FIN=1
时,表明此报文段的发送方数据已经发送完毕,并要求释放运输连接
窗口大小
:接受与发送端的缓存大小;窗口指的是发送本报文段一方的接受窗口
,窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量。`总之,窗口值作为接受方让发送方设置其发送窗口的依据;窗口字段明确指出了现在允许对方发送的数据量,窗口值是经常在变化的
校验和
紧急指针
:它指出本报文段中的紧急数据的字节数。
选项
最大报文段长度(MSS)
: MSS是一个TCP报文段中的数据字段的最大长度
·窗口扩大选项
时间戳
:两个作用用来计算往返时间RTT,发送方在发送报文段时把当前时钟的时间值放入时间戳字段,接受方在确认该报文段时把时间戳复制到时间戳会送回答字段。
抓包分析
TCP的传输连接管理
传输连接由3个阶段:
建立连接
,数据传送
,和联结释放
TCP连接的地址
每一条TCP连接唯一的被通信两端的两个端点(即两个套接字)所确定
套接字socket=(IP地址:端口号)
TCP建立过程中解决的问题
- 要使得每一方都知道对方的存在
- 要允许双方协商一些参数(如最大窗口值,是否实用窗口扩大选项和时间戳选项以及服务质量等)
- 能够对运输实体资源(如缓存大小,连接表中的项目等)进行分配
TCP连接的建立
(1)首先A向B发出连接请求报文段,这时首部中的同步位SYN=1,同时选择一个初始序号 seq=x。TCP规定,SYN报文段不能携带数据,但要消耗掉一个序号。这时,A进入SYN-SENT状态。【备注:序号指的是 TCP 报文段首部20字节里的序号,TCP 连接传送的字节流的每一个字节都按顺序编号,具体可以看看 TCP 可靠传输实现的原理】
(2)B收到请求后,向A发送确认。在确认报文段中把SYN和ACK位都置为1,确认号是ack=x+1,同时也为自己选择一个初始序号seq=y。请注意,这个报文段也不能携带数据,但同样要消耗掉一个序号。这时B进入SYN-RCVD状态。
(3)A收到B的确认后,还要向B给出确认。确认报文段的ACK置为1,确认号ack=y+1,而自己的序号seq=x+1。这时,TCP连接已经建立,A进入ESTABLISHED 状态,当B收到A的确认后,也会进入 ESTABLISHED 状态。
TCP建立握手的状态
为什么三次握手
谓已失效的连接请求报文段是这样产生的。A发送连接请求,但因连接请求报文丢失而未收到确认,于是A重发一次连接请求,成功后建立了连接。数据传输完毕后就释放了连接。现在假定A发出的第一个请求报文段并未丢失,而是在某个网络节点长时间滞留了,以致延误到连接释放以后的某个时间才到达B。本来这是一个早已失效的报文段。但B收到此失效的连接请求报文段后,就误以为A又发了一次新的连接请求,于是向A发出确认报文段,同意建立连接。假如不采用三次握手,那么只要B发出确认,新的连接就建立了。
由于A并未发出建立连接的请求,因此不会理睬B的确认,也不会向B发送数据。但B却以为新的运输连接已经建立了,并一直等待A发来数据,因此白白浪费了许多资源。
采用TCP三次握手的方法可以防止上述现象发生。例如在刚才的情况下,由于A不会向B的确认发出确认,连接就不会建立。
SYNSYN泛洪攻击原理
那么假如在这“握手”的过程中,客户端程序因为莫名崩溃等原因,收到SYN+ACK报文后不再回以ACK,服务端将如何处置呢?这时服务端会“优雅地”再等等,会不会是发送的包丢失了呢?于是重新发送一遍SYN+ACK,再收不到来自客户端的ACK响应的话,就把这次连接丢弃掉。这个过程大约会“优雅地”持续分钟级,这个持续时间被称作SYN timeout时间。如果只有个别这样的异常情况,目标服务端处理起来自是毫不费力;可如果大量这样的情况出现,对服务端来说就不堪重负了。这是为什么呢?
对于SYN泛洪攻击的防范,优化主机系统设置是常用的手段。如降低SYN timeout时间,使得主机尽快释放半连接的占用;又比如采用SYN cookie设置,如果短时间内连续收到某个IP的重复SYN请求,则认为受到了该IP的攻击,丢弃来自该IP的后续请求报文。此外合理地采用防火墙等外部网络安全设施也可缓解SYN泛洪攻击。
TCP连接的释放(四次挥手)
(1)客户端 A 的 TCP 进程先向服务端发出连接释放报文段,并停止发送数据,主动关闭 TCP 连接。释放连接报文段中 FIN=1,序号为 seq=u,该序号等于前面已经传送过去的数据的最后一个字节的序号加1。这时,A进入 FIN—WAIT-1 (终止等待1)状态,等待 B 的确认。TCP 规定,FIN报文段即使不携带数据,也要消耗掉一个序号。这是 TCP 连接释放的第一次挥手。
(2)B收到连接释放报文段后即发出确认释放连接的报文段,该报文段中,ACK=1,确认号为ack=u+1,其自己的序号为v,该序号等于B前面已经传送过的数据的最后一个字节的序号加1。然后B进入CLOSE—WAIT(关闭等待)状态,此时TCP服务器进程应该通知上层的应用进程,因而A到B这个方向的连接就释放了,这时TCP处于半关闭状态,即A已经没有数据要发了,但B若发送数据,A仍要接受,也就是说从B到A这个方向的连接并没有关闭,这个状态可能会持续一些时间。这是TCP连接释放的第二次挥手。
(3)A收到B的确认后,就进入了FIN—WAIT(终止等待2)状态,等待B发出连接释放报文段,如果B已经没有要向A发送的数据了,其应用进程就通知TCP释放连接。这时B发出的链接释放报文段中,FIN=1,确认号还必须重复上次已发送过的确认号,即ack=u+1,序号seq=w,因为在半关闭状态B可能又发送了一些数据,因此该序号为半关闭状态发送的数据的最后一个字节的序号加1。这时B进入LAST—ACK(最后确认)状态,等待A的确认,这是TCP连接的第三次挥手。
(4)A收到B的连接释放请求后,必须对此发出确认。确认报文段中,ACK=1,确认号ack=w+1,而自己的序号seq=u+1,而后进入TIME—WAIT(时间等待)状态。这时候,TCP连接还没有释放掉,必须经过时间等待计时器设置的时间2MSL后,A才进入CLOSED状态,时间MSL叫做最长报文寿命,RFC建议设为2分钟,因此从A进入TIME—WAIT状态后,要经过4分钟才能进入到CLOSED状态,而B只要收到了A的确认后,就进入了CLOSED状态。二者都进入CLOSED状态后,连接就完全释放了,这是TCP连接的第四次挥手。
为什么A在TIME_WAIT状态后必须等待2MSL(最长报文段寿命Maximum segment Lifetime)的时间呢?
- 为了保证A发送的最后一个ACK报文段能够到达B。即最后这个确认报文段很有可能丢失,那么B会超时重传,然后A再一次确认,同时启动2MSL计时器,如此下去。如果没有等待时间,发送完确认报文段就立即释放连接的话,B就无法重传了(连接已被释放,任何数据都不能出传了),因而也就收不到确认,就无法按照步骤进入CLOSE状态,即必须收到确认才能close。
- A在发送完最后一个
ACK
报文段后,再经过2msl
,就可以使得本连接持续时间内所产生的所有报文段都从网络中消失,这样就可以使得下一个新连接中不会出现这种旧的连接请求报文daunt
TCP的优先状态机
客户端状态迁移
CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->
TIME_WAIT`->CLOSED
以上流程是在程序正常的情况下应该有的流程,从书中的图中可以看到,在建立连接时,当客户端收到SYN报文的ACK以后,客户端就打开了数据交互地连接。而结束连接则通常是客户端主动结束的,客户端结束应用程序以后,需要经历FIN_WAIT_1,FIN_WAIT_2等状态,这些状态的迁移就是前面提到的结束连接的四次握手。
服务端状态迁移状态
服务器的状态可以用如下的流程来表示:
CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED
在建立连接的时候,服务器端是在第三次握手之后才进入数据交互状态,而关闭连接则是在关闭连接的第二次握手以后(注意不是第四次)。而关闭以后还要等待客户端给出最后的ACK包才能进入初始的状态。
2MS等待状态
书中给的图里面,有一个TIME_WAIT等待状态,这个状态又叫做2MSL状态,说的是在TIME_WAIT2发送了最后一个ACK数据报以后,要进入TIME_WAIT状态,这个状态是防止最后一次握手的数据报没有传送到对方那里而准备的(注意这不是四次握手,这是第四次握手的保险状态)
TCP协议如何实现可靠传输???
1、停止等待协议(自动重传请求ARQ)
停止等待
就是每发送完一个分组就停止发送,等待对方的确认,在收到确认后再发送下一分组。
自动重传请求ARQ;表明重传的请求是自动进行的,接收方不需要请求发送方重传某个出错的分组
2、超时重传改进,滑动窗口协议和连续ARQ协议
发送窗口
:位于发送窗口的5个分组都可以连续发送出去,而不需要等待对方的确认- 连续ARQ协议规定,发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置。
- 接受方一般都是采用
累积确认
的方式,这就是说,接收方不必对收到的分组逐个发送确认,而是在收到几个分组后,对按序到达的最后一个分组发送确认
,这就是说:到达这个分组为止的所有分组都已经正确收到了- 累积确认优点:容易实现,即使确认丢失也不必重传。缺点:不能向发送方反映出接受已经正确收到
所有分组的信息
3、以字节为单位的滑动窗口
数据报没有丢失
发送窗口
:在没有收到B的确认的情况下,A可以连续把窗口内的数据都发送出去,凡是已经发送过的数据,在未收到确认之前都必须暂时保留,以便在超时重传时使用。
发送窗口通常只是发送缓存的一部分。已被确认的数据应当从发送缓存中删除,因此发送缓存和发送窗口的后延是重合的。发送应用程序最后写入发送缓存的字节减去最后被确认的字节,就是保留在发送缓存中的被写入的字节数
发送窗口的确定
虽然
A的发送窗口是根据B的接受窗口设置
的,但在同一时刻,A的发送窗口并不总是和B的接受窗口一样大,这是因为通过网络传送窗口值需要经历一定的时间滞后,发送方A还可能根据当时的拥塞情况适当减小自己的发送窗口的数值
数据报丢失的可靠传输
对于不按序到大的数据
对于不按序到达的数据,
- 可以将不按序到达的数据一律丢弃,那么接受窗口的管理比较简单,但这样做对网络资源的利用不利(因为发送方会重复传送较多的数据)
- 通常可以将不按顺序到大的数据 先临时存放在窗口中,等到字节流中所缺少的字节收到后,再按序交付上层的应用进程
超时重传时间的选择
TCP的发送方在规定的时间内没有收到确认后就要重传已发送的报文段。
- 如果把超时重传时间设置的太短,就会引起很多报文段不必要的重传
- 但若把超时重传时间设置的过长,则又网络的空闲时间增大,降低了传输效率
TCP协议如何实现流量控制
所谓流量控制就是让发送方的发送速率不要太快,要让接受方来得及接收
接收方为了保证能以何时的速度处理数据包,所以希望动态调整发送方的速率,所以才会有窗口这一说法
rwnd:(receiver window:接收窗口
)`
通过控制发送和接受窗口大小来控制流量==发送端根据接受端的实际情况来确定发送的窗口大小
接收端向发送端发送的窗口不为0报文丢失咋办
为了解决这个问题,
TCP
为每一个连接设有一个持续计时器
,只要TCP
连接的一方收到对方的零窗口通知,就启动持续计数器
,若持续计数器设置的时间到期,就发送一个零窗口探测报文段
,而对方就在确认这个探测报文段时给出现在的窗口值
,如果窗口仍然是零,那么收到的这个歌报文段的一方就重新设置持续计数器
TCP协议拥塞控制(互联网的整体情况)
拥塞出现的条件:对资源需求的综合>可用资源
1拥塞控制
是一个全局性的过程,设计到所有的主机,所有的路由器,以及与降低网络传输性能有关的所有因素
流量控制
:往往旨在给定的发送端和接受端之间的点对点通信量的控制,它所要做的就是抑制发送端发送数据的速率,以便接受端来得及接受
拥塞控制的一般原理
在某段时间,若对网络中某易资源的需求超过了该资源所提供的的可用部分,网络的性能就变坏。这种情况就叫做
拥塞
引起拥塞的几种常见原因
- 某节点的缓存容量变小,到达该节点的分组因无存储空间暂存而不得不被放弃
- 处理机的速率太慢可能引起网络的拥塞,简单的将处理机的速率提高,可能会使上述情况缓解一些,但往往又会将瓶颈转移到其他地方
拥塞控制与流量控制的区别
拥塞控制
:防止过多的数据注入到网络,这样可以使网络中的路由器或链路不致过载,拥塞控制所要做的都有一个前提,就是网络能够承受现有网络负荷。拥塞控制是一个全局性过程,涉及到所有主机,所有的路由器,以及与降低网络传输性能有关的所有因素。
流量控制
:往往指点对点通信量的控制,是个端对端的问题。流量控制所要做的事情就是移植发送单发送数据的速率,以便使得接受端来得及接受
几种拥塞控制的方法
慢开始和拥塞避免
发送方维持一个叫做
拥塞窗口cwnd(congesttion window
的状态变量,拥塞窗口的大小取决于`网络的拥塞程度,并且动态的变化。发送放让自己的发送窗口等于拥塞窗口
发送方控制
拥塞窗口的
原则是:只要网络没有出现拥塞,拥塞窗口就再增大一些,以便能把更大的分组发送出去。但只要网络出现拥塞,拥塞窗口就减小一些,以减少注入到网络中的分组数
慢开始
:当主机开始发送数据时,如果立即把大量数据字节注入到网络中,那么就有可能引起网络拥塞
,因为现在并不清楚网络的负荷情况
,需要进行探测下,由小到大逐渐增大拥塞窗口数值。使用慢开始算法后,每经过一个传输轮次,拥塞窗口cwnd
就加倍。
为了防止拥塞窗口cwnd
缓慢的增大,还需要设置一个慢开始门限状态变量,当拥塞窗口小于这个值时采用慢开始
,当大于这个值时采用拥塞表面算法
拥塞避免
:让拥塞窗口缓慢的增大,即每经过一个往返时间RTT
就把发送方的拥塞窗口cwnd
加1,而不是加倍
,这样,拥塞窗口cwnd
按照`线性规律缓慢的增长,比慢开始算法的拥塞窗口增长速率缓慢的多
慢开始和拥塞控制阶段出现拥塞
无论在慢开始阶段还是拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有按时收到确认),就要把
慢开始门限ssthresh
设置为出现拥塞时发送窗口值的一般,然后把拥塞窗口cwnd
重新设置为1,执行慢开始算法。这样做的目的是迅速减少主机发送到网络中的分组数,使得发送拥塞的路由器有足够的时间把队列中积压的分组处理完毕
快重传与快恢复
快重传
:发送方只要一连接受到三个重复确认
就应当立即重传对方尚未收到的报文段,而不必继续等待M3
设置的重传计时器到期,由于发送双方能尽早重传尚未被确认的报文段,因此采用快重传后可以使得整个网络的吞吐量提高约20%
与快重传配合使用的还有快恢复
- 当发送方连续收到三个重复确认时,就执行乘法减小算法,把慢开始门限ssthresh减半,这是为了预防网络发生拥塞(注意接下来不执行慢开始)
- 由于发送方现在认为网络很可能没有发生网络拥塞,因此与慢开始不同之处是现在不执行慢开始算法(即拥塞窗口
cwnd
现在不设置为1),而是把cwnd
值设置为慢开始门限ssthresh减半后的数值,然后开始执行拥塞避免算法
发送窗口的实际值
从
流量控制
和拥塞控制
两方面入手确定发送窗口大小