【网络系列】TCP到底是怎么保证可靠性的?快来get一下!

协议字段

  1、16位源端口:标识数据从哪个进程来。
  2、16位目的端口:标识数据到哪个进程去。
  3、32位序号:用于进行包序管理。
  4、32位确认序号:用于进行包序管理。
  5、4位首部长度:用于描述头部信息长度,单位是4个字节。tcp协议头部长度最小为20字节,最大为当4位首部长度最大时即为15 * 4 = 60字节。
  6、6位保留:用于保留下来存储新的属性和数据。
  7、6位标志位:用于标志当前tcp信息的属性和类型,常见的有URG/ACK/PSH/RST/SYN/FIN。

CWR(Congestion Window Reduce):拥塞窗口减少标志被发送主机设置,
用来表明它接收到了设置ECE标志的TCP包,发送端通过降低发送窗口的大小来降低发送速率

ECE(ECN Echo):ECN响应标志被用来在TCP3次握手时表明一个TCP端是具备ECN功能的,
并且表明接收到的TCP包的IP头部的ECN被设置为11。更多信息请参考RFC793。

URG(Urgent):该标志位置位表示紧急(The urgent pointer) 标志有效。
该标志位目前已经很少使用参考后面流量控制和窗口管理部分的介绍。

ACK(Acknowledgment):取值1代表Acknowledgment Number字段有效,这是一个确认的TCP包,取值0则不是确认包。
后续文章介绍中当ACK标志位有效的时候我们称呼这个包为ACK包,使用大写的ACK称呼。

PSH(Push):该标志置位时,一般是表示发送端缓存中已经没有待发送的数据,接收端不将该数据进行队列处理,而是尽可能快将数据转由应用处理。
在处理 telnet 或 rlogin 等交互模式的连接时,该标志总是置位的。

RST(Reset):用于复位相应的TCP连接。通常在发生异常或者错误的时候会触发复位TCP连接。

SYN(Synchronize):同步序列编号(Synchronize Sequence Numbers)有效。该标志仅在三次握手建立TCP连接时有效。
它提示TCP连接的服务端检查序列编号,该序列编号为TCP连接初始端(一般是客户端)的初始序列编号。
在这里,可以把TCP序列编号看作是一个范围从0429496729532位计数器。通过TCP连接交换的数据中每一个字节都经过序列编号。在TCP报头中的序列编号栏包括了TCP分段中第一个字节的序列编号。
类似的后续文章介绍中当这个SYN标志位有效的时候我们称呼这个包为SYN包。

FIN(Finish):带有该标志置位的数据包用来结束一个TCP会话,但对应端口仍处于开放状态,
准备接收后续数据。当FIN标志有效的时候我们称呼这个包为FIN包。

  8、16位窗口大小:标志传输窗口的大小,这块牵扯到tcp协议的传输特性和机制,在后续进一步讲解。
  9、16位校验和:校验数据一致性。
  10、16位紧急指针:带外数据。
  11、40字节选项数据:有时没有有时有,但长度必须是4的整数倍字节。
  除选项外其他头信息一共20字节,这是最小头信息长度。

TCP连接管理机制
三次握手建立连接

客户端发送连接请求后进入SYN_SENT状态,服务端的监听套接字调用listen处于LISTEN状态,客户端会向服务端发送一个SYN包,服务端收到后会转变状态为SYN_REVD状态,成功后向客户端发送SYN+ACK报文表示收到连接请求,之后客户端会再次确认,转换状态为ESTABLISHED并返回ACK包表示连接成功,服务端收到ACK后进入ESTABLISHED状态。

在这里插入图片描述

四次挥手断开连接

首先客户端(假设客户端先发起断开连接请求 比如shutdown或close)进入FIN_WAIT1状态,发送FIN包请求关闭连接,服务端收到后切换状态为CLOSE_WAIT状态,并且发送ACK包确认收到请求,客户端收到回复会进入FIN_WIAT2状态。随后服务端切换状态为LAST_ACK并且主动发送FIN包确认是否断开连接,客户端收到后切换状态为TIME_WAIT并发送ACK包给服务端,服务端收到后切换状态为CLOSED正式断开连接,但是客户端此时并不会真正断开连接,处在TIME_WAIT状态的客户端会在此继续等待一段时间,之后才会改变状态为CLOSED。
在这里插入图片描述

为什么?

在tcp连接和断开过程中有很多疑问,为什么要三次握手四次挥手?为什么客户端断开连接还要等待?
  为什么握手要三次才能建立连接?两次行不行?四次呢?
  我们都注意到握手和挥手都需要客户端和服务端双方各发送一个SYN和收到一个ACK包才能算成功,这是为了防止网络传输过程中由于延迟,丢包等问题对数据造成丢失或延迟,因此客户端和服务端此时都要确认对方此时是在线的是可以连接的。我们可以想象这样的场景,在挥手过程中如果只有两次的话,客户端发送一个连接请求,服务端收到后就表示已经建立连接,这样是十分不安全的,如果这个连接请求因为延迟被耽误了很久,服务端接收到报文的时候客户端此时已经关闭了,那么这个连接就是失败的,但是服务端却表示成功了,那着肯定是不合理不安全的。因此服务端也必须要发送一个SYN包确认此时客户端在线,需要服务端回复后才能确认连接建立成功,因此两次握手是不安全的,但是四次连接也是没有必要的,服务端在建立连接时确认客户端在线的SYN报文是可以和回复报文一起发送的,因此三次即可。
  为什么挥手要四次,三次可以么?
  和建立连接同理,服务端和客户端需要各发送一次FIN进行一次确认,但是这里为什么不可以将服务端的FIN和ACK放在一起发送?因为在连接关闭后,连同socket及其相应的缓冲区都会关闭,清空数据,那么如果此时缓冲区中还有信息的话信息也会一起丢失,因此客户端发送FIN包后服务端不能将回应ACK和确认FIN一起发送,服务端会在用户接收缓冲区中所有数据后才会发送FIN确认关闭请求,然后关闭套接字。
  TIME_WAIT有什么用,为什么客户端关闭连接后要等待?要等待多久?
  如果没有TIME_WAIT,客户端在发送最后一次ACK后就直接关闭的情况下,如果此时最后一次ACK包文丢失,服务端很久并没有收到包文,它会再次重发最后一次FIN包,如果此时客户端又重启了一个同端口的客户端准备再次建立连接,此时却接收到服务端发来的FIN包就会陷入混乱,因此客户端在此时需要等待。至于等待多久此时需要2个MSL的时间,一个MSL时间表示数据包在网络中的生命周期,它最久只能在网络中存活这么久,如果还没有成功则会销毁这个包,也就是丢包,等待两个MSL时间是为了让客户端自己发送的包以及以及服务端如果重发FIN包都能够要么接收到,要么都消亡在网络中不对后续连接造成影响,等待2个MSL时间已经足够保守极大减少之前连接会影响到之后连接情况。

保活机制

默认情况下,通信双方7200s没有数据往来,每隔75s向对方发送一个保活探测数据包,要求对方进行相应,若是得到相应则认为连接正常,若是连续9次没有得到相应,则认为连接断开,将socket状态置为CLOSE_WAIT。

确认应答机制

TCP给发送的所有数据中的每一字节都进行了编号,假如说客户端首先给服务端发送了1-1000号数据,服务端如果接收到所有数据会返回1001ACK表示前1000字节的数据都已经收到了,但是如果返回的不是1001或者压根没有返回,客户端就会知道中间有丢包,于是为了可靠传输则会重传,于是有了超时重传机制。

超时重传机制

如果在客户端发送了1-1000号数据后服务端返回了1001ACK,此时客户端发送了1001-2000号数据,但是服务端给我们迟迟不见发送ACK确认,于是客户端就会认为1001-2000号数据丢包则会重新发送1001-2000号数据。
  当然客户端收不到ACK也有可能是ACK丢包,因此客户端会依然重发数据,此时服务端可能会存在大量重复数据,服务端会根据编号来辨别重复数据,并且如果客户端之后发送了2001-3000号数据,并且收到了3001号ACK则客户端虽然没有收到2001号ACK也会认为之前所有的数据都已经收到。
  至于多久才算超时,Linux是以500ms作为一个单位以整数倍作为超时时间,以指数形式增长,当重传到一定次数后还收不到ACK则认为网络出现异常,强制关闭连接。

确认数据有序和无误

超时重传机制和确认应答机制只能保证所有的包都不丢包,但是并不能保证包有序到达并且数据无误,这就要用到TCP头信息中的序号/确认序号来对包文进行排序,如果服务端先收到了2001-3000号包但没有收到1001-2000号数据服务端则暂时不会向用户表示自己收到了2001-3000号数据,会在此等待收到1001-2000号数据为止,并且收到数据后对包文进行排序和整理,以及通过校验和对包文数据进行校验。

滑动窗口机制

我们之前讨论都是在一次传输一次应答的情况下讨论的,但是这种通信方式过于缓慢,于是TCP是可以同时发送多个数据传输而不用非要每一条传输都接收ACK才会发送下一条数据,这样大大可以提高性能。但是如果发送过快,而网络状况不好,全部丢包,服务端一条都收不到或者只能零零散散接收到一些片段,则会导致客户端大量的重传包文,十分影响效率,因此引入滑动窗口机制。
  在介绍滑动窗口之前,我们还要知道一个概念即MSS,最大数据长度,这个大小往往是在三次握手期间就已经确定下来的,标识一个包文最大只能传输这么大的数据。知道这个概念后,我们就要开始思考一个问题,TCP允许同时发送多个数据包,但是为了防止大量丢包该怎么做呢?没错,呢就是限制能够同时发送的数据包的数量,这就是滑动窗口成立的基础。
  滑动窗口大小决定了能够无需等待确认应答的情况下可以继续发送数据的最大值。假如说我们在三次握手期间确定MSS=1024,滑动窗口win=4096,则表示客户端向服务端可以暂时不等待确认应答最多可以发送4096/1024=4个数据包,假设一开始客户端窗口框住的数据区域为1-4096,并且同时发送4个数据包完毕后,客户端就必须停下来等待确认应答。如果我们的第一个包1-1024号数据已经成功发送并且收到了响应ACK1025则表示一号包中数据发送成功,则客户端的窗口会向后滑动一个MSS大小框住接下来的数据1025-5120(假设滑动窗口大小并没有改变),然后继续向服务端发送窗口滑动后出现的新的一个数据包,以此类推,直到发出所有数据包并接受所有响应,此时滑动窗口应该已经滑到了数据末尾。窗口大小越大,网络吞吐量越高。
  停等协议:每一条数据收到回复后才会发送下一条,用于网络极差情况。
  回退N步协议:从丢包位置开始,往后的数据重新进行传输,用于网络一般的情况。
  选泽重传协议:丢那个重传哪个,用于网络极好情况

快速重传机制

任意一条数据丢失,发送方都要等待一个超时后才会进行重传,效率较低;因此接收方如果前面的数据还没收到,收到了后面的数据,则直接要求重传前面的数据。
假设窗口还是win=4096,MSS=1024我们的第一个包1-1024已经成功接收到了ACK,说明服务端接收到了1-1024的数据,但是服务端此时迟迟收不到1025-2048的数据,尽管后面的数据都已经收到,此时服务端会连续不断发送1025ACK提醒客户端我想要的是1025-2048数据。
一旦客户端连续三次收到相同的ACK则会知道对应的数据包丢失重新发送对应的数据包,这个机制叫做快速重传机制。
必须是三次:避免数据并没有丢失,而是延迟到达。

流量控制

同时得益于滑动窗口,我们可以控制传输数据的速度和大小,控制网络吞吐量。但是滑动窗口的大小并不是一成不变的,服务端在接收数据过程中如果缓冲区满了无法继续接收数据则会造成大量丢包情况,于是此时服务端可以通过改变窗口大小控制数据传输大小。服务端可以将自己缓冲区的大小放进TCP头部信息的窗口大小字段中,告诉客户端自己缓冲区大小,当缓冲区逐渐变满的过程中服务端每次发送ACK都会重新调整滑动窗口大小,告诉客户端你传慢点我收不下了,当大小为0时表示缓冲区已满,只有等用户从缓冲区提取信息后服务端才会加大窗口大小继续接收数据,由此做到流量控制。

拥塞控制

滑动窗口的大小并不是一开始就是最大的,因为要考虑到网络状况,一开始滑动窗口的大小只有1,用于试探网络状况,当确认网络状况没有问题的时候才会逐渐以指数级别增长速度继续增长,但是到达一个阈值后停止继续增长。如果传输过程中出现丢包需要重传情况则会将阈值缩小为原先的一半,并将滑动窗口置回1。这个过程用一句话形容就是慢启动,快增长,客户端想尽快将数据发送给对方,但是又要避免网络造成太大压力的折中方案。
在这里插入图片描述

延迟应答机制

客户端将数据发送给服务端后,服务端收到数据后并不会立刻回复ACK,因为刚接收完数据存储在缓冲区中用户还没有取走数据,因为流量控制机制此时必然要调小窗口大小,这样会影响传输速度,影响网络吞吐量,于是服务端会稍微在此等待片刻再做应答,这个时间一般是200ms左右,操作系统不同时间也不同,而操作系统也许处理数据速度很快10ms就取走数据,此时缓冲区数据被取走缓冲区又恢复到无数据状态,也就不用调小窗口大小控制传输速度了,这样可以保持网络吞吐量,提高传输效率。

捎带应答机制

如果在进行确认回复的时候,刚好有数据要发送,那就顺带把ACK与数据集成为一条数据进行发送,这就是捎带应答机制。

提供字节流服务

有序的,可靠的,基于连接的,双向的一种以字节为单位的进行传输的方式。
  一个TCP套接字在被创建后,同时在内核中创建一个发送缓冲区和一个接收缓冲区,既可以读数据也可以写数据,这样的模式被称为全双工。在调用send发送数据后会将数据先读取到缓冲区中,操作系统会将数据积累到合适的长度在合适的时机进行发送。在接收数据时也是从接收缓冲区中读取数据。正因为缓冲区的存在,使得TCP的数据传输十分自由,写一个数据可以一次写完也可以分段多次写,读也一样,正因为字节流这样灵活的服务导致了接下来的问题——粘包问题(可能将多条数据当作一条处理)。

TCP粘包问题

首先要明确一点UDP不会粘包,因为在UDP头信息中就已经存储了数据大小信息,根据这个信息可以分辨出这个包的边界,因此不会出现取数据时取出下一个报文的数据的情况。但是由于TCP面向字节流传输灵活因此无法明确两个包之间的边界。
  
  如何解决呢?明确两个包之间的边界。
  要想解决粘包问题我们只能通过在应用层对数据的处理来明确数据边界了。有以下几种做法。
  1、如果数据是定长的,例如传输的是结构或者类这样的块状结构,只需要每次都保证读取定长的数据即可。(实际数据较小则需要补位)
  2、如果是变长的数据,可以约定在数据头部添加一个字段,表示这个包数据的长度,获取这个包的话只读取这么长的数据即可。(例如http、udp都有报头长度字段)
  3、也可以在不影响的数据下在数据末尾添加分割符,标识这个包数据的结束。(需要对特殊字符进行转义,避免产生二义)
  以上这些方法都可以区分包与包之间数据的边界,从而解决粘包问题。

TCP总结

以上讲了TCP这么多的机制,我们可以将其分类总结,TCP之所以复杂的原因是它为了保证可靠性但又尽可能的在提升效率。

可靠性
  1、校验和。
  2、序列号。
  3、确认应答机制。
  4、超时重传机制。
  5、连接管理。
避免丢包
  1、流量控制。
  2、滑动窗口。
  3、拥塞控制。
提高性能
  1、快速重传。
  2、延迟应答机制。
  3、捎带应答机制。

TCP应用

基于TCP的应用层协议:HTTP/HTTPS/SSH/FTP/SMTP。

TCP与UDP的对比

通过对TCP与UDP的介绍,我们现在已经很清楚TCP与UDP各自的特点及各自的优势。
  对于TCP协议,适用于要求安全性高,传输可靠的情况下,例如文件传输,重要状态更新等情况。
  对于UDP协议,适用于实时性高,速度要求快的情况下,例如视频传输,通信领域等。

如何用UDP实现可靠传输

UDP本身是不可靠的,可能会有大量丢包的情况发生,因此我们想要UDP实现可靠传输可以参考TCP在应用层实现TCP的一些可靠机制,例如在应用层利用序号确定包序,引入确认应答和超时重传保证不丢包等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
计算机网络作业七及解答 "计算机网络作业七及解答 " "计算机网络作业〔7〕 " "一、单项选择题 " " 1.TCP规定HTTP( )进程的端口号为80。 " " A.客户 B.解析 " " C.效劳器 D.主机 " " 2.A和B建立了TCP连接,当A收到确认号为100确实认报文段时,表示( " ")。 " " A.报文段99已收到 " " B.报文段100已收到 " " C.末字节序号为99的报文段已收到 " " D.末字节序号为100的报文段己收到 " " " "3.在采用TCP连接的数据传输阶段,如果发送端的发送窗口值由1000变为20" "00,那么发送端在收到一个确认之前可以发送( )。 " " A.2000个TCP报文段 B.2000B " " C.1 000B D.1 000个TCP报文段 " " 4.为保证数据传输的可靠性TCP采用了对( )确认的机制。 " " A.报文段 B.分组 " " C.字节 D.比特 " " 5.以下关于TCP格式的描述中,错误的选项是( )。 " " A.报长度为20"~60B,其中固定局部为20B " " B.端口号字段依次表示源端口号与目的端口号 " " C.报长度总是4的倍数个字节 " " D.TCP校验和伪首部中IP分组的协议字段为1 7 " " 6.滑动窗口的作用是( )。 " " A.流量控制 B.拥塞控制 " " C.路由控制 D.过失控制 " " 7.在TCP中,发送方的窗口大小取决于( )。 " " A.仅接收方允许的窗口 " " B.接收方允许的窗口和发送方允许的窗口 " " C.接收方允许的窗口和拥塞窗口 " " D.发送方允许的窗口和拥塞窗口 " " 8.以下关于TCP 作原理与过程的描述中,错误的选项是( )。 " " A.TCP连接建立过程需要经过"三次握手〞的过程 " " " "B.当TCP传输连接建立之后,客户端与效劳器端的应用进程进行全双工的字" "节流传输 " " " "C.TCP传输连接的释放过程很复杂,只有客户端可以主动提出释放连接的请" "求 " " D.TCP连接的释放需要经过"四次挥手〞的过程 " " 9.以下关于TCP窗口与拥塞控制概念的描述中,错误的选项是( )。 " " A.接收端窗(rwnd)通过TCP首部中的窗口字段通知数据的发送方 " " B.发送窗口确定的依据是:发送窗El=Min[接收端窗口,拥塞窗口 " " C.拥塞窗口是接收端根据网络拥塞情况确定的窗口值 " "D.拥塞窗口大小在开始时可以按指数规律增长 " " 10.TCP使用三次握手协议来建立连接,设A、B双方发送报文的初始序列 " "号分别为X和Y,A发送( )的报文给B,B接收到报文后发送( )的报文给A,然" "后A发送一个确认报文给B便建立了连接。(注:ACK的下标为捎带的序号) " " A.SYN=1,序号=X B.SYN=1,序号=X+1,ACKx=I " " C.SYN=1,序号:Y D.SYN=1,序号=Y,ACKy+1=1 " " A.SYN=1,序号=X+1 B.SYN=1,序号=X+1,ACKx=l " " C.SYN=1,序号=Y,ACKx+1=1 D.SYN=1,序号=Y,ACKy+1=1 " "11.TCP"三次握手〞过程中,第二次"握手〞时,发送的报文段中( )标 " "志位被置为1。 " " A.SYN B.ACK " " C.ACK 和RST D.SYN和ACK " "12.A和B之间建立了TCP连接,A向B发送了一个报文段,其中序号字段seq=2" "00确认号字段ACK=201,数据局部有2个字节,那么在B对该报文确实认报文 " "段中( ) " " A.seq=202,ACK=200 B.seq=201,ACK=201 " " C.seq=201,ACK=202 D.seq=202,ACK=201 " "13.一个TCP连接的数据传输阶段,如果发送端的发送窗口值由2000变为300" "0,意昧着发送端可以( )。 " " A.在收到一个确认之前可以发送3000个TCP报文段 " " B.在收到一个确认之前可以发送1000B " " C.在收到一个确认之前可以发送3000B " " D.在收到一个确认之前可以发送2000个TCP报文段 " "14.在一个TCP连接中,MSS为1 " "KB,当拥塞窗口为34KB时发生了超时事件。如果在接下来的4个RTT内报文段" "传输都是成功的,那么当这些报文段均得到确认后,拥塞窗口的大小是( " ")。 " " A.8KB B.9KB " " C.1 6KB D.1 7KB " "1 5.在一个TCP连接中,MSS为1 KB,当拥塞窗口为34KB " "H寸收到了3个冗余

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值