zoukankan      html  css  js  c++  java
  • 计算机网络(四)--TCP基础知识讲解

    TCP传输的数据单元是报文段,报文段分为首部、数据两部分

    TCP首部

    首部的前20字节是固定长度,后面的4n字节根据需要增加的选项

    字段解释:图中标示单位为bit,不是byte

      1、源端口、目的端口:占用2byte,实现分用功能(TCP通过端口把请求分发到应用层不同的应用程序)

      2、序号:占用4byte,范围[0,2^32-1],序号增加到最大,就会重新回到0,也就是使用的mod2^32运算

      TCP面向字节流的,同一个TCP连接中传送的字节流中每个字节都是按照顺序编号,整个要传送的字节流的初始序号在连接建立的时候设置,首部

    中的序号指的是本报文段所发送的数据的第一个字节的序号。

      3、确认号ack:占用4byte,指的是希望收到对方的下一个报文段的首个字节的序号

      4、数据偏移:占用4bit,指的是TCP报文段首部的长度,因为选项的长度不确定,所以数据偏移的存在是很有必要的,数据偏移的最大长度

    60byte,所以选项的长度不超过40byte

      5、保留:占6bit

      6、紧急URG(URGent):当URG=1时,紧急指针字段有效,应用程序告诉TCP发送端有紧急数据需要发送,于是TCP把紧急数据插入到本报文段数据

    最前面,后面的数据仍然是普通数据,需要和紧急指针配合使用

      7、确认ACK:ACK=1生效,在连接建立之后发送的所有报文段ACK都要置为1

      8、推送PSH:发送方把PSH置为1,并立即创建一个报文段发送出去,接收方收到PSH=1的报文段,就尽快的交付给应用程序,不需要等到整个接

    缓存填满之后再向上交付。但是很少使用

      9、复位RST:当RST=1时,表明TCP连接出现严重差错,必须释放连接,然后重新建立连接,还可以用来拒绝一个非法的报文段或者拒绝打开一

    非法连接。RST也称为重置位或重建位

      10、同步SYN:在连接建立时同步序号。

      11、终止FIN:用来释放一个连接

      12、窗口:占用2byte,指的是发送方的接收窗口,而不是发送窗口

      窗口值的作用就是:

        从本报文段的首部确认号开始,接收方允许发送报文数据量,之所以有这个限制,这是因此接收方的数据缓存是有限的。

      窗口值作为接收方让发送方设置其发送窗口的依据。

      13、检验和:占用2byte,通过加上伪首部,检验首部和数据

      14、紧急指针:占用2byte,只有URG=1才有效,指的是紧急数据的大小,紧急数据末尾在报文段的位置,窗口为0的时候也可以发送紧急数据。

      15、选项:长度可变,最大40byte

      cwnd:发送端窗口(congestion window)

      rwnd:接收端窗口(receiver window)

      最大报文段长度MSS:实际指的是TCP报文段中数据字段的最大长度,MSS尽量大一点,只要在网络层传输不需要分片就行

    可靠传输的工作原理

      TCP发送的报文段交给IP层传输,网络层提供不可靠的服务,所以,TCP必须采用合适的措施使得两个运输层之间的通信变得可靠

    理想的传输条件:

      1).传输信道不产生差错

      2).不管发送方发送数据的速度有多快,接收方总能来得及接收数据

    A是发送方,B是接收方

    这种理想情况下才不需要采取措施实现可靠传输,然后实际上不是这样的,需要可靠性传输协议

    停止等待协议:

      传输的数据单元称为分组,每发送一个分组就停止发送,知道得到对方的确认,然后再发送下一个分组

    超时重传:

      为每个发送的分组设置一个超时计数器,A只要经过一段时间没有收到确认,就认为刚才的分组丢失,重新发送刚才的分组

    确认丢失:

      确认丢失了,A没有收到,重新发送给B一个分组,B又收到重传的分组M1,要采用两个行动:

      1).丢弃这个重复的分组

      2).向A发送确认

     

     

    确认迟到:

      A收到重复的确认立马丢弃,B收到重复的分组,也要丢弃,并且重新确认分组

     

      上述的可靠性传输协议就是自动重传请求(ARQ Automatic Repeat reQuest),在不可靠的网络环境实现可靠的通信

    总结:

      重传的请求是自动进行的,接收方不需要主动要求发送方重传某个错误的分组

      停止等待协议优点就是简单,但是信道利用率太低,为了提高利用率,发送方可以不使用等待停止协议,采用流水线传输,

    就需要了解连续ARQ协议和滑动窗口协议

    连续ARQ协议

      位于发送窗口中的每个分组都可以按顺序连续发送出去,不需要等待对方的确认,这样信道的利用率就提高了

      发送方:每收到一个确认,发送窗口向前滑动一个分组的位置

      接收方:不必对收到每个分组逐个发送确认,而是在收到几个分组后,对按次序到达的最后一个分组发送确认,就表示:到这个分组为

    止之前的所有分组都收到了,这就是累计确认

    滑动窗口

      以字节为单位,已经发送的数据,在没收到确认的时候,都要暂时保存,以便超时重传。后沿后面的部分都是已发送且收到确认。后沿只

    不动或者前移。前沿的前面部分是不允许发送的,可以前移、不动、后移(不建议)

    例如:A收到B发来的确认报文段,如下图

      发送窗口的序号表示允许发送的序号。窗口越大,发送方就可以在收到对方确认之前发送更多的数据,因此可以获得更高的传输效率。接收

    方会把自己的接收窗口数值放到窗口字段中发给对方。所以,A的发送窗口一定不能大于B的接受窗口数值。除此之外,发送窗口还受到网络拥塞

    程度的影响

      现在假设A发送了序号4 - 13的数据,发送窗口位置不变,但发送窗口内有5个字节(红色部分4 - 8)是已发送但未收到确认,而前面5个字节

    (9 - 13)允许发送但尚未发送

    上图中,P1,P2,P3分别代表着:

      P3-P1=A的发送窗口

      P2-P1=已发送但未收到确认的字节数

      P3-p2=允许发送但尚未发送的字节数,也称为可用窗口

    B的接收窗口:

      接收窗口大小为10,接受窗口4 - 13是允许接收的,B收到5和6的数据,但是4的数据没收到(丢失了,或者滞留在网络某节点),数据没按顺序

    到达,B只能对按序到达的数据中的最高序号进行确认,因此B发送的确认报文段中确认号还是31(即期望收到的序号),而不能是5或6

      假如,A最终把9-13也发送成功,P2和P3重合,可用窗口为0,B发送了确认,但是滞留在网络中,为了保证可靠传输,A只能认为B还没收到,超

    过后进行重传(超时计数器控制时间),之后重置计数器,直到收到B确认位置

    发送/接收的缓存和窗口

      图咱就不画了,应该能看懂,画图真的花时间的。如果实在看不懂,自己看书,在《计算机网络第七版》P223

      发送方的应用程序把字节流写入TCP的发送缓存,接收方的应用程序从TCP的接收缓存中读取字节流

    发送缓存:

      1、应用程序传送给发送方TCP准备发送的数据

      2、已发送但尚未收到确认的数据

    发送窗口是发送缓存的一部分,已确认的数据从缓存中删除。发送方应用程序必须控制写入缓存的速率,否则没有空间存放

    接收缓存:

      1、用来存放按序达到的,但未被接收方应用程序读取的数据

      2、为按序到达的数据

      如果收到的分组检测出有误差,直接丢弃。如果接收方应用程序来不及读取收到的数据,接收缓存会被填满,接收窗口就为0了,反之,接收

    窗口会变大,但不能超过接收缓存的大小。

    注意点:

      1、不按序到达的数据如何处理,无明确规定。通常先临时存放在接收窗口中,等到缺少的字节到达后,再按序交付上层的应用程序

      2、TCP要求接收方有累计确认的功能,这样可以减少传输开销

      3、TCP的通信是全双工通信,每一方都有自己的发送窗口和接收窗口,要搞清楚

     

    超时重传时间的选择:我选择放弃,你们自己看吧。。。

     

    选择确认SACK:

      当收到的报文段没有差错,只是未按照序号,中间缺少一些序号的数据,通过SACK只传送缺少的数据

    TCP的流量控制

      点对点通信量的控制

    1、利用滑动窗口实现流量控制

      让发送方的发送速度不要太快,能让接收方来得及接收

      ACK表示标志位,ack表示确认字段的值

      利用滑动窗口机制很方便在TCP连接上实现对发送方的流量控制

    PS:上面第二行,A发送序号101到200,应该是还能发送200字节,笔误了

      在连接建立的时候,B告诉A(rwnd=400),发送方的cwnd不能超过接收方给出的rwnd的范围,TCP的窗口单位为字节,不是报文段

      上面这个流程应该很好理解了。。。

      上述流程存在一个问题:B向A发送rwnd=0的报文段后,B的接收缓存又有了新的空间,发送rwnd=400,但是丢失了,这时候A等待B发送非零

    窗口的通知,B等待A发送数据,可能导致死锁。这个问题通过持续计数器解决

    持续计数器工作原理:

      只要收到零窗口报文段,就会启动,设置的时间到期后,发送一个探测报文段,对方收到后给出现在的窗口值,如果为零,重置时间,

    不为零,打破死锁

    2、TCP的传输效率

      通过TCP中广泛使用的Nagle算法和解决糊涂窗口综合征的方式配合使用,最终达到:发送方不发送很小的报文段,接收方也不会有一点小的窗口

    大小信息就通知对方

    2、TCP的拥塞控制

    拥塞:网络中某一资源的需求超过该资源所能提供的可用部分,性能就会变差,也就是对资源的需求 > 可用资源

    1、一般原理:

      防止过多的数据注入到网络,这样就可以使网络中的路由器或链路不至于过载,是一种全局性的过程

    流量控制:

      点对点通信量的控制,是抑制发送端发送数据的效率,以便接收端来得及接收

    拥塞控制和流量控制最简单的对比:一台计算机传输数据和500台计算机传输数据(考虑的是整个网络的负载能力)的区别

    出现网络拥塞的因素很多:

      1).当某个节点缓存的容量太小,到达该节点的某些分组会被丢弃,简单的扩大缓存空间无法解决拥塞问题,可能导致网络的性能更差

      2).处理机处理的效率太慢

      在网络负载的增加,吞吐量的增加速率逐渐减少。为达到饱和,有一部分输入分组被丢失了。当网络进入拥塞时,吞吐量还会下降,设置降到

    零,出现死锁

    2、拥塞控制方法:

      基于窗口的拥塞控制:发送方维护一个拥塞窗口的状态变量。大小取决于网络的拥塞程度,动态变化。发送方让发送窗口等于拥塞窗口

      控制拥塞窗口的原则:如果网络没有发生拥塞,可以把拥塞窗口设置大一点,以便发送更多的分组,提高网络利用率,但是如果发生拥塞,

    就是减少拥塞窗口的大小,减少注入到网络中的分组,以便缓解网络中的拥塞。

    判断发生网络拥塞的依据就是出现超时,不考虑丢弃分组

    3、TCP基于拥塞控制的算法有以下四种:

    3.1).慢开始

      从小到大逐渐增大发送窗口,也就是组件增加拥塞窗口的值,从cwnd初始为1开始启动,指数启动只有在TCP连接建立和网络出现超时时才

    使用。每经过一个传输轮次,拥塞窗口 cwnd 就加倍。一个传输轮次所经历的时间其实就是往返时间RTT。不过“传输轮次”更加强调:把拥塞

    窗口cwnd所允许发送的报文段都连续发送出去,并收到了对已发送的最后一个字节的确认。

      另外,慢开始是指在TCP开始发送报文段时先设置cwnd=1,使得发送方在开始时只发送一个报文段(目的是试探一下网络的拥塞情况),然后

    再逐渐增大cwnd。为了防止拥塞窗口cwnd增长过大引起网络拥塞,还需要设置一个慢开始门限ssthresh状态变量(如何设置ssthresh)。

    慢开始门限ssthresh的用法如下:

      当 cwnd < ssthresh 时,使用上述的慢开始算法。

      当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法。

      当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞控制避免算法。

    3.2).拥塞避免

      让拥塞窗口cwnd缓慢增大,每经过一个往返时间RTT就把cwnd+1,而不是加倍,线性规律缓慢增加,到达ssthresh后,为了避免拥塞开始尝试

    线性增长

      我用的画图工具几乎没法画折线图,只能直接截图了,大家凑活看吧

      无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(超时),就要把慢开始门限ssthresh = cwnd/2(但不能小于2)。

    同时设置cwnd = 1,执行慢开始算法。

      个别报文段在网络中丢失,但实际上网络并没有发生拥塞。发送发收不到确认,就会产生超时,被误认为网络拥塞,这样就会产生问题。

    为了解决这个问题使用快重传算法,可以让发送方尽早知道有个别报文段丢失

    拥塞控制并不能完全避免拥塞

    3.3).快重传

      首先要求接收方每收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方),发送方只要一连收到三

    个重复确认就知道接收方丢包了,快速重传丢包的报文,而不必继续等待M3设置的重传计时器到期。TCP马上设置cwnd = 1。由于发送

    方尽早重传未被确认的报文段,因此采用快重传后可以使整个网络吞吐量提高约20%。

      如果发送方知道只是丢失个别报文段,不启动慢开始,而是使用快恢复算法

    3.4).快恢复

    特点:

      直接从ssthresh线性增长。

    与快重传配合使用,其过程有以下两个要点:

      1、当发送方连续收到三个重复确认,就执行“乘法减小”算法,把慢启动门限ssthresh减半。这是为了预防网络发生拥塞。请注意:接下

    去不执慢开始算法。

      2、由于发送方现在认为网络很可能没有发生拥塞,发送方调整ssthresh = cwnd/2,同时设置cwnd = ssthresh,然后开始执行拥塞

    避免算法,使拥塞窗口缓慢地线性增大。

    拥塞控制流程图:

    发送方窗口的上限值 = Min [ rwnd, cwnd ]

    当rwnd < cwnd 时,是接收方的接收能力限制发送方窗口的最大值。

    当cwnd < rwnd 时,则是网络的拥塞限制发送方窗口的最大值。

    也就是说,rwnd和cwnd中min,控制发送发发送数据的速率

    TCP运输连接管理

    TCP三次握手

      为了确保数据能到达目标,TCP协议采用三次握手

      用户发送HTTP request通过TCP connection连接服务器,这个连接可以一直保持着的,第一个HTTP完成三次握手,第二个请求就不需要进行

    三次握手了

      1、最开始两段TCP都是处于CLOSED,A主动打开连接,B被动打开连接

      2、B的TCP服务器进程创建传输控制模块TCB,准备接收客户端的请求,处于LISTEN

      3、A也创建TCB后

        3.1).一次握手:A向B发送连接请求报文段,同步位SYN=1,选择一个初始序号seq=x。SYN报文段不能携带数据,但是消耗一个序号,然后处

    SYN-SENT状态

        3.2).二次握手:B收到报文段,如果同意,发送确认报文段。SYN=ACK=1,确认号ack=x+1,为自己选择初始序号seq=y。这个报文段也不能

    带数据,也消耗一个序号,处于SYN-RCVD

        3.3).三次握手:client收到Server的确认报文段,还要给Server返回确认报文段。ACK=1,ack=y+1,seq=x+1(ACK报文段可以携带数据,如果

    携带不消耗序号,所以,下一个数据报文段的序号还是x+1),这时Client处于ESTABLISHED,Server收到Client的确认报文之后,也处于

    ESTABLISHED

      第三次的作用:防止已失效的连接请求报文突然又传到接收方,就以为这是一个新的连接请求,而发送方并不承认这个请求,就会浪费这个连接

    SYN攻击

      在三次握手的过程中,当server发送ACK+SYN包给client,client发送ACK给server,在server还没收到的时候,这时的TCP连接称为半连接,

    收到之后才是establish状态

      SYN攻击就是伪造大量的虚假IP地址,不断向server发送SYN包,server恢复确认,并且等待确认返回,由于源地址都是虚拟的,server不断

    发送SYN+ACK直到超时,这些SYN包将占用未连接队列,导致正常的SYN请求因为队列满了而被丢弃,从而引起网络阻塞甚至系统瘫痪

      这是一种典型的DDOS攻击,检测的方式:当server有大量半连接状态且源IP地址都是随机的,可以断定遭到SYN攻击了。

    为什么不是两次握手?

      如果client发送的报文段没有丢失,而是在某个网络节点被滞留,然后过了一段时间传递到server,这时已经是一段过期的报文段,server

    同意建立连接,而client现在并没有发送请求,不会发送请求,这样就会浪费server的资源,所以采用三次握手就可以避免这种情况

    四次挥手:断开连接

    第一次挥手:

      TCP发送一个FIN(结束,即使不携带数据,也要消耗一个序号),用来关闭客户端到服务端的连接。此时A处于FIN-WAIT-1状态。u等于前

    已发送过的数据的最后一个字节的序号+1。然后B进入CLOSE-WAIT状态,TCP服务器通知应用程序,从A到B的连接就释放了,此时TCP连接处

    HALF-CLOSE状态,但是B到A的连接没有关闭(Client是A,Server是B),这时如果B发送报文,A还是要接收的

    第二次挥手:

      B返回一个ACK(确认位),ack=u+1(FIN消耗一个序号)。v等于B之前已发送的数据的最后一个字节的序号+1。等待B发送连接释放报文段。

      A收到之后处于FIN-WAIT-2

    第三次挥手:

      如果B不再向A发送数据,应用程序通知B释放连接,发送一个FIN=1,seq=w,ack=u+1到A,seq为w(因为HALF-CLOSE状态的B可能有发送一些数据

    了),Server关闭Client的连接,B处于LAST-ACK。

    第四次挥手:

      A发送报文段到B,ACK=1,seq=u+1,ack=w+1。这时A处于TIME-WAIT状态。这时TCP连接还没有释放,经过2MSL(时间等待计时器设置的2MSL,MSL

    是最长报文段寿命,建议设置2minute)后,A才进入CLOSED。之后才能创建新的连接。当A撤销TCB之后,结束这次TCP连接

    为什么需要经过2MSL才进入CLOSED,原因:

      1、为了保证A发送的最后一个ACK报文段能够达到B

      2、防止已经失效的连接请求报文段出现在本连接中,这样可以使这次连接中产生的所有报文段从网络中消失

    为什么是4次挥手呢,ACK和FIN不同时发送给client?

      因为在关闭连接时,发送FIN给对方,只是表明我不想发送数据,但是我还是可以接收数据的,但是对方是否关闭发送数据通道,需要上层

    应用层来决定,因此,ACK和FIN都是分开发送的

    TCP的有效状态机

    上图中,粗实线的箭头表示客户进程的正常变迁,虚线箭头表示服务器进程的正常变迁,细线箭头表示异常变迁。

    什么是粘包、拆包?

      TCP根据缓冲区的实际情况进行包的划分,业务上分为:

      1、拆包:一个完整的包可能会被TCP分为多个包进行发送

      2、粘包:多个小的包也可能被封装成一个大的包进行发送

    粘包、拆包产生的原因?

      1、应用程序写入的字节大小大于Socket发送缓冲区大小

      2、进行MSS大小的TCP,MSS是最大报文段长度的缩写,是TCP报文段中的数据字段最大长度,MSS=TCP报文段长度-TCP首部长度

      3、以太网的Payload大于MTU,进行IP分片,MTU是最大传输单元的缩写,以太网的MTU为1500字节

    粘包、拆包解决策略

      由于底层的TCP无法理解上层的业务数据,所以在底层是无法保证数据包不被拆分和重组的,这个问题只能通过上层的应用协议栈设计来解决,

    根据业界的主流协议的解决方案,可以归纳如下:

      消息定长,例如每个报文的大小固定为200字节,如果不够空位补空格

      包尾增加回车换行符进行分割,例如FTP协议

      将消息分为消息头和消息体,消息头中包含表示长度的字段,通常涉及思路为消息头的第一个字段使用int32来表示消息的总长度更复杂的应用

    层协议

    同步/异步/阻塞/非阻塞

    同步阻塞:相当于一个线程在等待。

    同步非阻塞:相当于一个线程在正常运行。

    异步阻塞:相当于多个线程都在等待。

    异步非阻塞:相当于多个线程都在正常运行。

    IO分类: 

    BIO:同步阻塞IO

    NIO:同步非阻塞IO jdk1.4

      API相对复杂,需要熟悉多线程,内部存在bug,例如epoll bug,有可能selector空轮询造成100%CPU

    AIO:异步非阻塞IO

     

    内容参考:计算机网络(第七版)

  • 相关阅读:
    python3 driver chrome This version of ChromeDriver only supports Chrome version 89
    centos7 conda 安装 tensorflow
    python3 selenium Google浏览器 自动登录
    Fiddler Script
    深夜看了张一鸣的微博,让我越想越后怕(转载)
    OpenCV相关库
    .NET 面试题汇总(带答案)
    Java面试题
    定制化知识图谱 项目介绍
    关于《社会主义经济理论》若干问题的思考《九》
  • 原文地址:https://www.cnblogs.com/huigelaile/p/10938857.html
Copyright © 2011-2022 走看看