tcp协议总结(tcp协议实验总结)

      最后更新:2023-09-09 07:38

      传输层协议(TCP, UDP)

      传输层定义了主机应用程序之间端到端的连通性。传输层中最为常见的两个协议分别是传输控制协议TCP(Transmission Control Protocol)和用户数据报协议UDP(User Datagram Protocol)。为了简化问题说明,本课程以Telnet为例描述相关技术。设备支持通过Telnet协议和Stelnet协议登录。使用Telnet,Stelnet v1协议存在安全风险,建议你使用STelnet v2登录设备。为了简化问题说明,本课程以FTP为例来描述相关技术。设备支持通过FTP协议,TFTP以及SFTP传输文件。使用FTP,TFTP,SFTP v1协议存在风险,建议使用SFTP v2方式进行文件操作。TCP是一种面向连接的传输层协议,提供可靠的传输服务。TCP是一种面向连接的端到端协议。TCP作为传输控制协议,可以为主机提供可靠的数据传输。TCP需要依赖网络协议为主机提供可用的传输路径。TCP允许一个主机同事运行多个应用进程。每台主机可以拥有多个应用端口,没对端口号,源和目标IP地址的组合唯一地标识了一个会话。端口分为知名端口和动态端口。有些网络服务会使用固定的端口,这类端口称为知名端口,端口号范围为 0~1023 。比如:FTP,HTTP,Telnet,SNMP服务均使用知名端口。动态端口范围 1024~65535 ,这些端口号一般不会固定分配给某个服务,也就是说许多服务都可以使用这些端口。只要运行的程序向系统提出访问网络的申请,那么系统就可以从这些端口号中分配一个供该程序使用。TCP通常使用IP作为网络层协议,这是TCP数据被封装在IP数据包内。TCP数据段由TCP Header(头部)和TCP Data(数据)组成。TCP最多可以有60个字节的头部,如果没有Options字段,正常的长度是20字节。TCP Header是由如上图标识一些字段组成,这里列出几个常用字段。注意:1)主机A(通常也叫客户端)发送一个标识了SYN数据段,标识期望与服务器A建立连接,此数据段的序列号(seq)为a;2)服务器A回复标识了SYN+ACK的数据段,此数据段的序列号(seq)为b,确认序列号为主机A的序列号加1(a+1),以此作为对主机A的SYN报文的确认。3)主机A发送一个标识了ACK的数据段,此数据段的序列号(seq)为a+1,确认序列号为服务器A的序列号加1(b+1),以此作为对服务器A的SYN报文段的确认。TCP是一种可靠的,面向连接的全双工传输层协议。TCP连接的简历是一个三次握手的过程。TCP的可靠传输还提现在TCP使用了确认技术来确保目的设备收到了从源设备发来的数据,并且是准确无误的。确认技术的工作原理如下:目的设备接收到源设备发送的数据段时,会向源端发送确认报文,源设备收到确认报文后,继续发送数据段,如此重复。如图所示,主机A向服务器A发送TCP数据段,为描述方便假设每个数据段的长度都是500个字节。当服务器A成功收到序列号是M+1499的字节以及之前的所有字节时,会以序列号M+1400+1=M+1500进行确认。另外,由于数据段N+3传输失败,所以服务器A未能收到序列号为M+1500的字节,因此服务器A还会再次以序列号M+1500进行确认。注意:上面说到,数据段 N+3 传输失败,那么第二次确认号M+1500,主机A会将N+3,N+4,N+5全部发送一次。TCP滑动窗口技术通过动态改变窗口大小来实现对端到端设备之间的数据传输进行流量控制。如图所示,主机A和服务器A之间通过滑动窗口来实现流量控制。为了方便理解,此例中只考虑主机A发送数据给服务器A时,服务器A通过滑动窗口进行流量控制。例子中:主机A向服务器发送4个长度为1024字节的数据段,其中主机的窗口大小为4096个字节。服务器A收到第3个字节之后,缓存区满,第4个数据段被丢弃。服务器以ACK3073(1024*3=3072)响应,窗口大小调整为3072,表明服务器的缓冲区只能处理3072个字节的数据段。于是主机A改变其发送速率,发送窗口大小为3072的数据段。主机在关闭连接之前,要确认收到来自对方的ACK。TCP支持全双工模式传输数据,这意味着统一时刻两个方向都可以进行数据的传输。在传输数据之前,TCP通过三次握手建立的实际上是两个方向的连接,一次在传输完毕后,两个方向的连接必须都关闭。TCP连接的建立是一个三次握手过程,而TCP连接的终止则要经过四次挥别。如图:1.主机A想终止连接,于是发送一个标识了FIN,ACK的数据段,序列号为a,确认序列号为b。2.服务器A回应一个标识了ACK的数据段,序列号为b,确认序号为a+1,作为对主机A的FIN报文的确认。3.服务器A想终止连接,于是向主机A发送一个标识了FIN,ACK的数据段,序列号为b,确认好为a+1。4.主机A回应一个标识了ACK的数据段,序列号为a+1,确认序号为b+1,作为对服务器A的FIN报文的确认。以上四次交互完成了两个方向连接的关闭。TCP断开连接的步骤,这个比较详细:https://blog.csdn.net/ctrl_qun/article/details/52518479UDP是一种面向无连接的传输层协议,传输可靠性没有保证。当应用程序对传输的可靠性要求不高时,但是对传输速度和延迟要求较高时,可以用UDP协议来替代TCP协议在传输层控制数据的转发。UDP将数据从源端发送到目的端时,无需事先建立连接。UDP采用了简单,容易操作的机制在应用程序间传输数据,没有使用TCP中的确认技术或滑动窗口机制,因此UDP不能保证数据传输的可靠性,也无法避免接受到重复数据的情况。UDP头部仅占8个字节,传输数据时没有确认机制(注意,但是有校验和)。UDP报文分为UDP报文头和UDP数据区域两个部分。报头由源端口,目的端口,报文长度以及校验和组成。UDP适合于实时数据传输,比如语音和视频通信。相比TCP,UDP的传输效率更高,开销更小,但是无法保证数据传输可靠性。UDP头部的标识如下:1)16位源端口号:源主机的应用程序使用的端口号。2)16位目的端口号:目的主机的应用程序使用的端口号。3)16位UDP长度:是指UDP头部和UDP数据的字节长度。因为UDP头部长度是8字节,所以字段的最小值为8。4)16位UDP校验和:该字段提供了与TCP校验字段同样的功能;该字段是可选的。使用UDP传输数据时,由应用程序根据需要提供报文到达确认,排序,流量控制等功能。主机A发送数据包时,这些数据包是以有序的方式发送到网络中的,每个数据包独立地在网络中被发送,所以不同的数据包可能会通过不同的网路径叨叨主机B。这样的情况下,先发送的数据包不一定先到达主机B。因为UDP数据包没有序号,主机B将无法通过UDP协议将数据包按照原来的顺序重新组合,所以此时需要应用程序提供报文的到达确认,排序和流量控制等功能(也就是说UDP报文的到达确认,排序和流量控制是应用程序来确定的)。通常情况下,UDP采用实时传输机制和时间戳来传输语音和视频数据。UDP适合传输对延迟敏感的流量,如语音和视频。在使用TCP协议传输数据时,如果一个数据段丢失或者接受端对某个数据段没有确认,发送端会重新发送该数据段。TCP重新发送数据会带来传输延迟和重复数据,降低了用户的体验。对于延迟敏感的应用,少量的数据丢失一般可以被忽略,这是使用UDP传输能够提升用户的体验。总结:1.TCP头部中的确认标识位有什么作用呢?TCP报文头中的ACK标识位用于目的端对已接受到数据的确认。目的端成功收到序列号为x的字节后,会以序列号x+1进行确认。2.TCP头部中有哪些标识位参与TCP三次握手?在TCP三次握手过程中,要使用SYN和ACK标识位来请求建立连接和确认建立连接。
      传输层协议(TCP, UDP)

      TCP协议总结

      Transmission Control Protocol,传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议TCP协议的目的是:在不可靠传输的IP层之上建立一套可靠传输的机制。TCP的可靠只是对于它自身来说的, 甚至是对于socket接口层, 两个系统就不是可靠的了, 因为发送出去的数据, 没有确保对方真正的读到(所以要在业务层做重传和确认机制)。可靠传输的第一要素是确认, 第二要素是重传, 第三要素是顺序。 任何一个可靠传输的系统, 都必须包含这三个要素。数据校验也是必要的。传输是一个广义的概念, 不局限于狭义的网络传输, 应该理解为通信和交互. 任何涉及到通信和交互的东西, 都可以借鉴TCP的思想。无论是在UDP上实现可靠传输或者创建自己的通信系统,无论这个系统是以API方式还是服务方式,只要是一个通信系统,就要考虑这三个要素。SeqNum的增加是和传输的字节数相关的。上图中,三次握手后,来了两个Len:1440的包,而第二个包的SeqNum就成了1441。然后第一个ACK回的是1441(下一个待接收的字节号),表示第一个1440收到了。网络上的传输是没有连接的,包括TCP也是一样的。而TCP所谓的“连接”,其实只不过是在通讯的双方维护一个“连接状态”,让它看上去好像有连接一样。所以,TCP的状态变换是非常重要的。查看各种状态的数量ss -ant | awk '{++s[$1]} END {for(k in s) print k,s[k]}'通过三次握手完成连接的建立三次握手的目的是交换通信双方的初始化序号,以保证应用层接收到的数据不会乱序,所以叫SYN(Synchronize Sequence Numbers)。ISN是不能hard code的,不然会出问题的。比如:如果连接建好后始终用1来做ISN,如果client发了30个segment过去,但是网络断了,于是client重连,又用了1做ISN,但是之前连接的那些包到了,于是就被当成了新连接的包,此时,client的Sequence Number可能是3,而Server端认为client端的这个号是30了。全乱了。RFC793中说,ISN会和一个假的时钟绑在一起,这个时钟会在每4微秒对ISN做加一操作,直到超过232,又从0开始。这样,一个ISN的周期大约是4.55个小时。因为,我们假设我们的TCP Segment在网络上的存活时间不会超过Maximum Segment Lifetime(MSL),所以,只要MSL的值小于4.55小时,那么,我们就不会重用到ISN。如果Server端接到了Clien发的SYN后回了SYN-ACK,之后Client掉线了,Server端没有收到Client返回的ACK,那么,这个连接就处于一个中间状态,即没成功,也没失败。于是,Server端如果在一定时间内没有收到的ACK会重发SYN-ACK。在Linux下,默认重试次数为5次,重试的间隔时间从1s开始每次都翻番,5次的重试时间间隔为1s, 2s, 4s, 8s, 16s,总共31s,第5次发出后还要等32s都知道第5次也超时了,所以,总共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 26 -1 = 63s,TCP才会断开这个连接。客户端给服务器发了一个SYN后,就下线了,于是服务器需要默认等63s才会断开连接,这样,攻击者就可以把服务器的SYN连接的队列耗尽,让正常的连接请求不能处理。于是,Linux下给了一个叫tcp_syncookies的参数来应对这个事:当SYN队列满了后,TCP会通过源地址端口、目标地址端口和时间戳打造出一个特别的Sequence Number发回去(又叫cookie),此时服务器并没有保留客户端的SYN包。如果是攻击者则不会有响应,如果是正常连接,则会把这个SYN Cookie发回来,然后服务端可以通过cookie建连接(即使你不在SYN队列中)。千万别用tcp_syncookies来处理正常的大负载的连接的情况。因为sync cookies是妥协版的TCP协议,并不严谨。应该调整三个TCP参数:tcp_synack_retries减少重试次数,tcp_max_syn_backlog增大SYN连接数,tcp_abort_on_overflow处理不过来干脆就直接拒绝连接因为TCP是全双工的,因此断开连接需要4次挥手,发送方和接收方都需要发送Fin和Ack。如果两边同时断连接,那就会就进入到CLOSING状态,然后到达TIME_WAIT状态。指的是报文段的最大生存时间,如果报文段在网络中活动了MSL时间,还没有被接收,那么会被丢弃。关于MSL的大小,RFC 793协议中给出的建议是两分钟,不过实际上不同的操作系统可能有不同的设置,以Linux为例,通常是半分钟,两倍的MSL就是一分钟,也就是60秒主动关闭的一方会进入TIME_WAIT状态,并且在此状态停留两倍的MSL时长。由于TIME_WAIT的存在,大量短连接会占有大量的端口,造成无法新建连接。主动关闭的一方发出 FIN包,被动关闭的一方响应ACK包,此时,被动关闭的一方就进入了CLOSE_WAIT状态。如果一切正常,稍后被动关闭的一方也会发出FIN包,然后迁移到LAST_ACK状态。CLOSE_WAIT状态在服务器停留时间很短,如果你发现大量的 CLOSE_WAIT状态,那么就意味着被动关闭的一方没有及时发出FIN包。TCP要保证所有的数据包都可以到达,所以,必需要有重传机制。接收端给发送端的Ack确认只会确认最后一个连续的包,比如,发送端发了1,2,3,4,5一共五份数据,接收端收到了1,2,于是回ack 3,然后收到了4(注意此时3没收到),此时的TCP会怎么办?我们要知道,因为正如前面所说的,SeqNum和Ack是以字节数为单位,所以ack的时候,不能跳着确认,只能确认最大的连续收到的包,不然,发送端就以为之前的都收到了但总体来说都不好。因为都在等timeout,timeout可能会很长不以时间驱动,而以数据驱动重传如果包没有连续到达,就ack最后那个可能被丢了的包,如果发送方连续收到3次相同的ack,就重传Selective Acknowledgment, 需要在TCP头里加一个SACK的东西,ACK还是Fast Retransmit的ACK,SACK则是汇报收到的数据碎版,在发送端就可以根据回传的SACK来知道哪些数据到了,哪些没有收到重复收到数据的问题,使用了SACK来告诉发送方有哪些数据被重复接收了经典算法:Karn/Partridge算法,Jacobson/Karels算法TCP必需要知道网络实际的数据处理带宽或是数据处理速度,这样才不会引起网络拥塞,导致丢包Advertised-Window:接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来接收端LastByteRead指向了TCP缓冲区中读到的位置,NextByteExpected指向的地方是收到的连续包的最后一个位置,LastByteRcved指向的是收到的包的最后一个位置,我们可以看到中间有些数据还没有到达,所以有数据空白区。发送端的LastByteAcked指向了被接收端Ack过的位置(表示成功发送确认),LastByteSent表示发出去了,但还没有收到成功确认的Ack,LastByteWritten指向的是上层应用正在写的地方。接收端在给发送端回ACK中会汇报自己的AdvertisedWindow = MaxRcvBuffer – LastByteRcvd – 1;收到36的ack,并发出了46-51的字节如果Window变成0了,发送端就不发数据了如果发送端不发数据了,接收方一会儿Window size 可用了,怎么通知发送端呢:TCP使用了Zero Window Probe技术,缩写为ZWP,也就是说,发送端在窗口变成0后,会发ZWP的包给接收方,让接收方来ack他的Window尺寸,一般这个值会设置成3次,每次大约30-60秒。如果3次过后还是0的话,有的TCP实现就会发RST把链接断了。如果你的网络包可以塞满MTU,那么你可以用满整个带宽,如果不能,那么你就会浪费带宽。避免对小的window size做出响应,直到有足够大的window size再响应。如果这个问题是由Receiver端引起的,那么就会使用David D Clark’s 方案。在receiver端,如果收到的数据导致window size小于某个值,可以直接ack(0)回sender,这样就把window给关闭了,也阻止了sender再发数据过来,等到receiver端处理了一些数据后windows size大于等于了MSS,或者receiver buffer有一半为空,就可以把window打开让send 发送数据过来。如果这个问题是由Sender端引起的,那么就会使用著名的 Nagle’s algorithm。这个算法的思路也是延时处理,他有两个主要的条件:1)要等到 Window Size >= MSS 或是 Data Size >= MSS,2)等待时间或是超时200ms,这两个条件有一个满足,他才会发数据,否则就是在攒数据。TCP_CORK是禁止小包发送,而Nagle算法没有禁止小包发送,只是禁止了大量的小包发送TCP不是一个自私的协议,当拥塞发生的时候,要做自我牺牲拥塞控制的论文请参看 《Congestion Avoidance and Control》主要算法有:慢启动,拥塞避免,拥塞发生,快速恢复,TCP New Reno,FACK算法,TCP Vegas拥塞控制算法TCP网络协议及其思想的应用TCP 的那些事儿(上)TCP 的那些事儿(下)tcp为什么是三次握手,为什么不是两次或四次?记一次TIME_WAIT网络故障再叙TIME_WAITtcp_tw_recycle和tcp_timestamps导致connect失败问题tcp短连接TIME_WAIT问题解决方法大全(1)- 高屋建瓴tcp短连接TIME_WAIT问题解决方法大全(2)- SO_LINGERtcp短连接TIME_WAIT问题解决方法大全(3)- tcp_tw_recycletcp短连接TIME_WAIT问题解决方法大全(4)- tcp_tw_reusetcp短连接TIME_WAIT问题解决方法大全(5)- tcp_max_tw_bucketsTCP的TIME_WAIT快速回收与重用浅谈CLOSE_WAIT又见CLOSE_WAITPHP升级导致系统负载过高问题分析Coping with the TCP TIME-WAIT state on busy Linux servers
      TCP协议总结

      TCP 详解

      title: TCP 总结date: 2018-03-25 09:40:24tags:categories:-计算机网络我们都知道 TCP 是位于传输层的协议,他还有一个兄弟就是 UDP ,他们两共同构成了传输层。显然他们之间有很大的区别要不然的话在传输层只需要一个就好了。其中最重要的区别就是一个面向连接另外一个不是,这个区别就导致了他们是否能够保证稳定传输,显然不面向连接的 UDP 是没办法保证可靠传输的,他只能靠底层的网络层和链路层来保证。我们都知道网络层采用的是不可靠的 IP 协议。好吧,网络层也保证不了可靠传输,所以 UDP 保证可靠传输只能依靠链路层了。而 TCP 就好说了他不仅仅有底层的链路层的支持,还有自己的面向链接服务来保证可靠传输。当然 TCP也不仅仅就是比 UDP 多了一个可靠传输,前面也说到了这只是他们之间一个重要的区别。其实他的三个重要特性就是它们之间的区别。* 可靠传输* 流量控制* 拥塞控制TCP 主要是 确认重传机制 数据校验 数据合理分片和排序 流量控制 拥塞控制 依靠来完成可靠传输的 , 下面详细介绍这几种保证可靠传输的方式。确认重传,简单来说就是接收方收到报文以后给发送方一个 ACK 回复,说明自己已经收到了发送方发过来的数据。如果发送方等待了一个特定的时间还没有收到接收方的 ACK 他就认为数据包丢了,接收方没有收到就会重发这个数据包。好的,上面的机制还是比较好理解的,但是我们会发现一个问题,那就是如果接收方已经收到了数据然后返回的 ACK 丢失,发送方就会误判导致重发。而此时接收方就会收到冗余的数据,但是接收方怎么能判定这个数据是冗余的还是新的数据呢?这就涉及到了 TCP 的另外一个机制就是采用序号和确认号,也就是每次发送数据的时候这个报文段里面包括了当前报文段的序号和对上面的报文的确认号,这样我们的接收方可以根据自己接受缓存中已经有的数据来确定是否接受到了重复的报文段。这时候如果出现上面所说的 ACK 丢失,导致接受重复的报文段时客户端丢弃这个冗余的报文段。好现在我们大致了解了确认重传机制,但是还有些东西还没有弄清楚,也就是 TCP 真正的实现究竟是怎样的。这就是我们要解决的第一个问题就是如何确认。这里涉及到两种确认方式,分别称为 累计确认(捎带确认)和单停等协议。用一张图来快速理解,就是每发送一次数据,就进行一次确认。等发送方收到了 ACK 才能进行下一次的发送。一样的也是采用的 ACK 机制,但是注意一点的是,并非对于每一个报文段都进行确认,而仅仅对最后一个报文段确认,捎带的确认了上图中的 203 号及以前的报文。总结:从上面可以看到累计确认的效率更加高,首先他的确认包少一些那么也就是在网络中出现的大部分是需要传输的数据,而不是一半的数据一半的 ACK ,然后我们在第二张图中可以看到我们是可以连续发送多个报文段的(究竟一次性能发多少这个取决于发送窗口,而发送窗口又是由接受窗口和拥塞窗口一起来决定的。),一次性发多个数据会提高网络的吞吐量以及效率这个可以证明,比较简单这里不再赘述!结论:显然怎么看都是后者比较有优势,TCP 的实现者自然也是采用的累计确认的方式!上文中的那个特定的时间就是超时时间,为什么有这个值呢? 其实在发送端发送的时候就为数据启动了一个定时器,这个定时器的初始值就是超时时间。超时时间的计算其实有点麻烦,主要是我们很难确定一个确定的值,太长则进行了无意义的等待,太短就会导致冗余的包。TCP 的设计者们设计了一个计算超时时间的公式,这个公式概念比较多,有一点点麻烦,不过没关系我们一点点的来。首先我们自己思考如何设计一个超时时间的计算公式,超时时间一般肯定是和数据的传输时间有关系的,他必然要大于数据的往返时间(数据在发送端接收端往返一趟所用的时间)。好,那么我们就从往返时间下手,可是又有一个问题就是往返时间并不是固定的我们有如何确定这个值呢?自然我们会想到我们可以取一小段时间的往返时间的平均值来代表这一时间点的往返时间,也就是微积分的思想!好了我们找到了往返时间(RTT),接下来的超时时间应该就是往返时间再加上一个数就能得到超时时间了。这个数也应该是动态的,我们就选定为往返时间的波动差值,也就是相邻两个往返时间的差。下面给出我们所预估的超时时间(TimeOut)公式:很好,看到这里其实你已经差不多理解了超时时间的计算方式了,只不过我们这个公式不够完善,但是思路是对的。我们这时候来看看 TCP 的实现者们采用的方式。好的,这就是 TCP 实现的超时时间的方式,但是在实际的应用中并不是一直采用的这种方式。假如说我们现在网络状态非常的差,一直在丢包我们根本没必要这样计算,而是采用直接把原来的超时时间加倍作为新的超时时间。总结:好的现在我们知道了在两种情况下的超时时间的计算方式,正常的情况下我们采用的上面的比较复杂的计算公式,也就是RTT+波动值否则直接加倍上面我们看到在发送方等待一个超时重传时间后会开始重传,但是我们计算的超时重传时间也不定就很准,也就是说我们经常干的一件事就会是等待,而且一般等的时间还挺长。那么可不可以优化一下呢?当然,在 TCP 实现中是做了优化的,也就是这里说到的快速重传机制。他的原理就是在发送方收到三个冗余的 ACK 的时候,就开始重传那个报文段。那么为什么是三个冗余的 ACK 呢?注意三个冗余的 ACK 其实是四个 ACK 。我们先了解一下发送 ACK 策略,这个是RFC 5681 文档规定的。好的,那么现在我们可以看到如果出现了三个冗余的 ACK 他只可能是发生了两次情况三,也就是发送了两个比期望值大的数据。但是注意出现情况三有两种可能,一个是丢包,另外一个是乱序到达。比如说我们现在是数据乱序到达的,我们来看一下。第一种乱序情况另外一种乱序丢包情况结论: 很显然我们可以看到,如果发生了乱序有可能会出现三次冗余 ACK,但是如果发现了丢包必然会有三次冗余 ACK 发生,只是 ACK 数量可能更多但是不会比三次少在我们发现丢包以后我们需要重传,但是我们重传的方式也有两种方式可以选择分别是GBN和SR翻译过来就是拉回重传和选择重传。好其实我们已经能从名字上面看出来他们的作用方式了,拉回重传就是哪个地方没收到那么就从那个地方及以后的数据都重新传输,这个实现起来确实很简单,就是把发送窗口和接受窗口移回去,但是同样的我们发现这个方式不实用干了很多重复的事,效率低。那么选择重传就是你想到的谁丢了,就传谁。不存在做无用功的情况。结论:TCP 实际上使用的是两者的结合,称为选择确认,也就是允许 TCP 接收方有选择的确认失序的报文段,而不是累计确认最后一个正确接受的有序报文段。也就是跳过重传那些已经正确接受的乱序报文段。数据校验,其实这个比较简单就是头部的一个校验,然后进行数据校验的时候计算一遍 checkSum 比对一下。在 UDP 中,UDP 是直接把应用层的数据往对方的端口上 “扔” ,他基本没有任何的处理。所以说他发给网络层的数据如果大于1500字节,也就是大于MTU。这个时候发送方 IP 层就需要分片。把数据报分成若干片,使每一片都小于MTU.而接收方IP层则需要进行数据报的重组。这样就会多做许多事情,而更严重的是 ,由于UDP的特性,当某一片数据传送中丢失时 , 接收方便无法重组数据报,将导致丢弃整个UDP数据报。而在 TCP 中会按MTU合理分片,也就是在 TCP 中有一个概念叫做最大报文段长度(MSS)它规定了 TCP 的报文段的最大长度,注意这个不包括 TCP 的头,也就是他的典型值就是 1460 个字节(TCP 和 IP 的头各占用了 20 字节)。并且由于 TCP 是有序号和确认号的,接收方会缓存未按序到达的数据,根据序号重新排序报文段后再交给应用层。流量控制一般指的就是在接收方接受报文段的时候,应用层的上层程序可能在忙于做一些其他的事情,没有时间处理缓存中的数据,如果发送方在发送的时候不控制它的速度很有可能导致接受缓存溢出,导致数据丢失。相对的还有一种情况是由于两台主机之间的网络比较拥塞,如果发送方还是以一个比较快的速度发送的话就可能导致大量的丢包,这个时候也需要发送方降低发送的速度。虽然看起来上面的两种情况都是由于可能导致数据丢失而让发送主机降低发送速度,但是一定要把这两种情况分开,因为前者是属于 流量控制而后者是拥塞控制,那将是我们后面需要讨论的事情。不要把这两个概念混了。其实说到流量控制我们就不得不提一下滑动窗口协议,这个是流量控制的基础。由于 TCP 连接是一个全双工的也就是在发送的时候也是可以接受的,所以在发送端和接收端同时维持了发送窗口和接收窗口。这里为了方便讨论我们就按照单方向来讨论。接收方维持一个接受窗口,发送方一个发送窗口。发送的时候要知道接受窗口还有多少空间,也就是发送的数据量不能超过接受窗口的大小,否则就溢出了。而当我们收到一个接收方的 ACK 的时候我们就可以移动接受窗口把那些已经确认的数据滑动到窗口之外,发送窗口同理把确认的移出去。这样一直维持两个窗口大小,当接收方不能在接受数据的时候就把自己的窗口大小调整为 0 发送窗口就不会发送数据了。但是有一个问题,这个时候当接收窗口再调大的时候他不会主动通知发送方,这里采用的是发送方主动询问。还是画个图看的比较直观:拥塞控制一般都是由于网络中的主机发送的数据太多导致的拥塞,一般拥塞的都是一些负载比较高的路由,这时候为了获得更好的数据传输稳定性,我们必须采用拥塞控制,当然也为了减轻路由的负载防止崩溃。这里主要介绍两个拥塞控制的方法,一个是慢开始,另外一个称为快恢复。那么问题来了,为什么需要序号呢?为什么又是三次握手而不是两次?以及什么是 SYN 洪泛攻击?这里需要说明一下的是最后的那个长长的 TIME_WAIT 状态一般是为了客户端能够发出 ACK 一般他的值是 1分钟 或者2分钟好了,今天真的写了不少,主要就是把 TCP 的可靠传输以及连接管理讲清楚了,以及里面的一下细节问题,真的很花时间。然后其他没有涉及到的就是关于 TCP 的头并没有详细的去分析,这个东西其实也不是很难,但是现在篇幅真的已经很大就先这样,头里面的都是固定的不需要太多的理解。
      TCP 详解

      网络编程(五)TCP详解

      考虑最简单的情况:两台主机之间的通信。这个时候只需要一条网线把两者连起来,规定好彼此的硬件接口,如都用 USB、电压 10v、频率 2.4GHz 等,这一层就是物理层,这些规定就是物理层协议。我们当然不满足于只有两台电脑连接,因此我们可以使用交换机把多个电脑连接起来,如下图:这样连接起来的网络,称为局域网,也可以称为以太网(以太网是局域网的一种)。在这个网络中,我们需要标识每个机器,这样才可以指定要和哪个机器通信。这个标识就是硬件地址 MAC。硬件地址随机器的生产就被确定,永久性唯一。在局域网中,我们需要和另外的机器通信时,只需要知道他的硬件地址,交换机就会把我们的消息发送到对应的机器。这里我们可以不管底层的网线接口如何发送,把物理层抽离,在他之上创建一个新的层次,这就是数据链路层。我们依然不满足于局域网的规模,需要把所有的局域网联系起来,这个时候就需要用到路由器来连接两个局域网:但是如果我们还是使用硬件地址来作为通信对象的唯一标识,那么当网络规模越来越大,需要记住所有机器的硬件地址是不现实的;同时,一个网络对象可能会频繁更换设备,这个时候硬件地址表维护起来更加复杂。这里使用了一个新的地址来标记一个网络对象:IP 地址。通过一个简单的寄信例子来理解 IP 地址。我住在北京市,我朋友 A 住在上海市,我要给朋友 A 写信:因此,这里 IP 地址就是一个网络接入地址(朋友 A 的住址),我只需要知道目标 IP 地址,路由器就可以把消息给我带到。在局域网中,就可以动态维护一个 MAC 地址与 IP 地址的映射关系,根据目的 IP 地址就可以寻找到机器的 MAC 地址进行发送。这样我们不需管理底层如何去选择机器,我们只需要知道 IP 地址,就可以和我们的目标进行通信。这一层就是网络层。网络层的核心作用就是提供主机之间的逻辑通信。这样,在网络中的所有主机,在逻辑上都连接起来了,上层只需要提供目标 IP 地址和数据,网络层就可以把消息发送到对应的主机。一个主机有多个进程,进程之间进行不同的网络通信,如边和朋友开黑边和女朋友聊微信。我的手机同时和两个不同机器进行通信。那么当我的手机收到数据时,如何区分是微信的数据,还是王者的数据?那么就必须在网络层之上再添加一层:运输层:运输层通过 socket(套接字),将网络信息进行进一步的拆分,不同的应用进程可以独立进行网络请求,互不干扰。这就是运输层的最本质特点:提供进程之间的逻辑通信。这里的进程可以是主机之间,也可以是同个主机,所以在 android 中,socket 通信也是进程通信的一种方式。现在不同的机器上的应用进程之间可以独立通信了,那么我们就可以在计算机网络上开发出形形式式的应用:如 web 网页的 http,文件传输 ftp 等等。这一层称为应用层。应用层还可以进一步拆分出表示层、会话层,但他们的本质特点都没有改变:完成具体的业务需求。和下面的四层相比,他们并不是必须的,可以归属到应用层中。最后对计网分层进行小结:这里需要注意的是,分层并不是在物理上的分层,而是逻辑上的分层。通过对底层逻辑的封装,使得上层的开发可以直接依赖底层的功能而无需理会具体的实现,简便了开发。这种分层的思路,也就是责任链设计模式,通过层层封装,把不同的职责独立起来,更加方便开发、维护等等。TCP 并不是把应用层传输过来的数据直接加上首部然后发送给目标,而是把数据看成一个字节 流,给他们标上序号之后分部分发送。这就是 TCP 的面向字节流特性:面向字节流的好处是无需一次存储过大的数据占用太多内存,坏处是无法知道这些字节代表的意义,例如应用层发送一个音频文件和一个文本文件,对于 TCP 来说就是一串字节流,没有意义可言,这会导致粘包以及拆包问题,后面讲。前面讲到,TCP 是可靠传输协议,也就是,一个数据交给他,他肯定可以完整无误地发送到目标地址,除非网络炸了。他实现的网络模型如下:对于应用层来说,他就是一个可靠传输的底层支持服务;而运输层底层采用了网络层的不可靠传输。虽然在网络层甚至数据链路层就可以使用协议来保证数据传输的可靠性,但这样网络的设计会更加复杂、效率会随之降低。把数据传输的可靠性保证放在运输层,会更加合适。可靠传输原理的重点总结一下有:滑动窗口、超时重传、累积确认、选择确认、连续 ARQ。停止等待协议要实现可靠传输,最简便的方法就是:我发送一个数据包给你,然后你跟我回复收到,我继续发送下一个数据包。传输模型如下:这种“一来一去”的方法来保证传输可靠就是停止等待协议(stop-and-wait)。不知道还记不记得前面 TCP 首部有一个 ack 字段,当他设置为 1 的时候,表示这个报文是一个确认收到报文。然后再来考虑另一种情况:丢包。网络环境不可靠,导致每一次发送的数据包可能会丢失,如果机器 A 发送了数据包丢失了,那么机器 B 永远接收不到数据,机器 A 永远在等待。解决这个问题的方法是:超时重传。当机器 A 发出一个数据包时便开始计时,时间到还没收到确认回复,就可以认为是发生了丢包,便再次发送,也就是重传。但重传会导致另一种问题:如果原先的数据包并没有丢失,只是在网络中待的时间比较久,这个时候机器 B 会受到两个数据包,那么机器 B 是如何辨别这两个数据包是属于同一份数据还是不同的数据?这就需要前面讲过的方法:给数据字节进行编号。这样接收方就可以根据数据的字节编号,得出这些数据是接下来的数据,还是重传的数据。在 TCP 首部有两个字段:序号和确认号,他们表示发送方数据第一个字节的编号,和接收方期待的下一份数据的第一个字节的编号。停止等待协议的优点是简单,但缺点是信道利用率太低。假定AB之间有一条直通的信道来传送分组这里的TD是A发送分组所需要的时间(显然TD = 分组长度 / 数据速率)再假定TA是B发送确认分组所需要的时间(A和B处理分组的时间都忽略不计)那么A在经过TD+RTT+TA时间后才能发送下一个分组,这里的RTT是往返时间,因为只有TD是采用来传输有用的数据(这个数据包括了分组首部,如果可以知道传输更精确的数据的时间,可以计算的更精确),所有信道利用率为为了提高传输效率,发送方可以不使用低效率的停止等待协议,而是采用流水线传输:就是发送方可以连续的发送多个分组,不必每发完一个分组就停下来等待对方的确认。这样可使信道上一直有数据不间断地在传送。显然这种传输方式可以获得很高的信道利用率停止等待协议已经可以满足可靠传输了,但有一个致命缺点:效率太低。发送方发送一个数据包之后便进入等待,这个期间并没有干任何事,浪费了资源。解决的方法是:连续发送数据包。也就是下面介绍的连续ARQ协议和滑动窗口协议连续 ARQ 协议模型如下:和停止等待最大的不同就是,他会源源不断地发送,接收方源源不断收到数据之后,逐一进行确认回复。这样便极大地提高了效率。但同样,带来了一些额外的问题:发送是否可以无限发送直到把缓冲区所有数据发送完?不可以。因为需要考虑接收方缓冲区以及读取数据的能力。如果发送太快导致接收方无法接受,那么只是会频繁进行重传,浪费了网络资源。所以发送方发送数据的范围,需要考虑到接收方缓冲区的情况。这就是 TCP 的流量控制。解决方法是:滑动窗口。基本模型如下:在 TCP 的首部有一个窗口大小字段,他表示接收方的剩余缓冲区大小,让发送方可以调整自己的发送窗口大小。通过滑动窗口,就可以实现 TCP 的流量控制,不至于发送太快,导致太多的数据丢失。连续 ARQ 带来的第二个问题是:网络中充斥着和发送数据包一样数据量的确认回复报文,因为每一个发送数据包,必须得有一个确认回复。提高网络效率的方法是:累积确认。接收方不需要逐个进行回复,而是累积到一定量的数据包之后,告诉发送方,在此数据包之前的数据全都收到。例如,收到 1234,接收方只需要告诉发送方我收到 4 了,那么发送方就知道 1234 都收到了。第三个问题是:如何处理丢包情况。在停止等待协议中很简单,直接一个超时重传就解决了。但,连续 ARQ 中不太一样。例如:接收方收到了 123 567,六个字节,编号为 4 的字节丢失了。按照累积确认的思路,只能发送 3 的确认回复,567 都必须丢掉,因为发送方会进行重传。这就是GBN(go-back-n)思路。但是我们会发现,只需要重传 4 即可,这样不是很浪费资源,所以就有了:选择确认 SACK。在 TCP 报文的选项字段,可以设置已经收到的报文段,每一个报文段需要两个边界来进行确定。这样发送方,就可以根据这个选项字段只重传丢失的数据了。第四个问题是:拥塞控制的问题也是通过窗口的大小来控制的,但是检测网络满不满是个挺难的事情,所以 TCP 发送包经常被比喻成往谁管理灌水,所以拥塞控制就是在不堵塞,不丢包的情况下尽可能的发挥带宽。水管有粗细,网络有带宽,即每秒钟能发送多少数据;水管有长度,端到端有时延。理想状态下,水管里面的水 = 水管粗细 * 水管长度。对于网络上,通道的容量 = 带宽 * 往返时延。如果我们设置发送窗口,使得发送但未确认的包为通道的容量,就能撑满整个管道。如图所示,假设往返时间为 8 秒,去 4 秒,回 4 秒,每秒发送一个包,已经过去了 8 秒,则 8 个包都发出去了,其中前四个已经到达接收端,但是 ACK 还没返回,不能算发送成功,5-8 后四个包还在路上,还没被接收,这个时候,管道正好撑满,在发送端,已发送未确认的 8 个包,正好等于带宽,也即每秒发送一个包,也即每秒发送一个包,乘以来回时间 8 秒。如果在这个基础上调大窗口,使得单位时间可以发送更多的包,那么会出现接收端处理不过来,多出来的包会被丢弃,这个时候,我们可以增加一个缓存,但是缓存里面的包 4 秒内肯定达不到接收端课,它的缺点会增加时延,如果时延达到一定程度就会超时重传TCP 拥塞控制主要来避免两种现象,包丢失和超时重传,一旦出现了这些现象说明发送的太快了,要慢一点。具体的方法就是发送端慢启动,比如倒水,刚开始倒的很慢,渐渐变快。然后设置一个阈值,当超过这个值的时候就要慢下来慢下来还是在增长,这时候就可能水满则溢,出现拥塞,需要降低倒水的速度,等水慢慢渗下去。拥塞的一种表现是丢包,需要超时重传,这个时候,采用快速重传算法,将当前速度变为一半。所以速度还是在比较高的值,也没有一夜回到解放前。到这里关于 TCP 的可靠传输原理就已经介绍得差不多。最后进行一个小结:当然,这只是可靠传输的冰山一角,感兴趣可以再深入去研究
      网络编程(五)TCP详解

      简述TCP的三次握手过程。

      TCP握手协议 在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接.第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手. 完成三次握手,客户端与服务器开始传送数据
      第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认。第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态。 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。完成三次握手,客户端与服务器开始传送数据。简版:首先A向B发SYN(同步请求),然后B回复SYN+ACK(同步请求应答),最后A回复ACK确认,这样TCP的一次连接(三次握手)的过程就建立了。三次握手我们先明确两个定义:1,client为数据发送方2,server为数据接收方好,下面进行三次握手的总结:1,client想要向server发送数据,请求连接。这时client向服务器发送一个数据包,其中同步位(SYN)被置为1,表明client申请TCP连接,序号为j。2,当server接收到了来自client的数据包时,解析发现同步位为1,便知道client是想要简历TCP连接,于是将当前client的IP、端口之类的加入未连接队列中,并向client回复接受连接请求,想client发送数据包,其中同步位为1,并附带确认位ACK=j+1,表明server已经准备好分配资源了,并向client发起连接请求,请求client为建立TCP连接而分配资源。 3,client向server回复一个ACK,并分配资源建立连接。server收到这个确认时也分配资源进行连接的建立。
      A与B建立TCP连接时:首先A向B发SYN(同步请求),然后B回复SYN+ACK(同步请求应答),最后A回复ACK确认,这样TCP的一次连接(三次握手)的过程就建立了!


      简述TCP的三次握手过程。

      本文由 在线网速测试 整理编辑,转载请注明出处。

          热门文章

          文章分类