传输层协议之TCP/UDP

目录

端口号

UDP协议

UDP协议的特点

UDP的应用场景

TCP协议

TCP协议格式

TCP是以段为单位发送数据

超时重传

TCP三次握手

TCP的四次挥手

滑动窗口

快速重传

延迟应答

捎带应答

流量控制

拥塞控制

TCP总结


传输层的作用:负责用户数据的传输与控制

对于IP地址来说,用来标记全网内的唯一一台主机,并且IP协议首部有一个字段用来标识上一层所采用的的是哪一层的传输协议,可以得到是TCP内容还是UDP内容。但是数据到达操作系统并不知道交给哪个进程去处理。对传输层的TCP和UDP协议引入端口号来标识一个进程。

端口号

通俗一点来说,端口号好比快递上的名字,快递的地址就好比IP地址,寄快递到地址后得知道交到哪个人的手上,当知道端口号时,就知道交给哪个进程去处理。

在服务器端,处理这些请求的进程一般是守护进程。例如HTTP的端口默认是80,对应http的服务端程序是httpd。当有http请求到来时,识别端口为80,然后将该请求交给httpd。

在操作系统中这些守护进程不需要逐个启动,而是启动一个可以超级守护进程inetd。这个进程的作用就是负责创建子进程,然后去执行进程程序替换,转化位各个服务进程。

端口号的大小16位,所以说端口号的范围0-65535。这些端口号被划分为知名端口号和动态分配的端口号。

知名端口号的范围是0-1023,例如HTTP的端口号80,HTTPS的端口号为443,SSH的端口号为22,所以在平常绑定端口号的时候就得避开这些端口号,防止发生冲突。

动态分配的端口号范围是 1024-65535。这些端口号由操作系统分配。

注意:一个进程可以绑定多个端口号,而一个端口号不可以绑定多个进程

UDP协议

UDP(User Datagram Protocol,用户数据报协议)。

下图是UDP协议的格式

UDP 8字节的报头,其中包括16位源端口号,16位目的端口号,16位UDP长度和16位UDP校验和

16位UDP长度包括:报头的长度+有效载荷的长度。16位UDP校验和,如果在接收端计算的校验和出错,则丢弃报文。

UDP协议的特点

1、无连接

双方通信前不需要建立连接,知道对方的IP地址和端口后就可以直接发送数据。

2、不可靠

没有确认应答机制重传机制不保证交付顺序,以及没有拥塞控制等可靠性保证的方法。

3、面向数据报

每一次发送数据都会告知有效载荷的长度,发送端发送n字节的数据,接收端也会以n字节位长度接收数据。

UDP的应用场景

虽然UDP有很多缺点,但是他相比较TCP更加的简单和高效。适用于下面的场景:

即时通信:直播、语音通信、广播。

包总量较少的通信:DNS。

基于UDP的应用层协议:NFS,TFTP,DHCP,DNS等。

总结

UDP是一种没有复杂的控制,提供面向无连接通信服务的一种协议。自己只提供作为传输层协议最基本的功能,甚至把部分控制转移给上层应用程序去处理(例如拥塞控制)。


TCP协议

TCP(Transmission Control Protocol,传输控制协议),是一种面向连接,可靠的传输层协议。TCP充分体现出其传输(滑动窗口、快速重传等)控制(确认应答、超时重传、流量控制、拥塞控制)的功能。

TCP协议格式

前四个字节和UDP一样,都是源端口号和目的端口号。

32位序号:它保证了数据包在接收端有序接收,除此之外还可以去除重复的数据包

32位确认序号:用来确认数据包是否收到,确认序号ACK = SEQ+1;

采用序号和确认序号的机制是为了实现可靠的数据传输,当发送端将数据发送之后等待对方进行确认应答,如果有确认应答,表明数据已经成功到达对端,否则很可能数据丢失。

上图为一个简单的确认应答的过程。

协议规定:收到确认序号是多少,默认确认序号以前的数据包都已经收到了。

TCP标准的报头长度是20字节,但是由于有选项这一浮动项,所以报头长度是浮动的。所以报头中有一个字段为4位首部长度:代表报头有多少四字节,4位的空间最大值为15,所以报头最大长度为4*15位60字节。可以看到TCP是没有标识有效载荷的长度的,这也体现出面向字节流的特性(可能会存在粘包问题)。

16位窗口大小:接收缓冲区剩余空间的大小。

6个标志位

  • SYN标志位:建立连接标志,如果该标志位被标记,说明是建立连接的数据包。
  • FIN 标志位:断开连接标志,如果该标志位被标记,说明是断开连接的数据包。
  • ACK标志位:确认标志位
  • PSH标志位:提示接收端应用程序立刻从TCP缓冲区把数据读走
  • RST标志位:对方要求重新建立连接,我们把携带RST标识的称为复位报文段

以下四种情况会发送RST包:

  1. 端口未打开。
  2. 请求超时。
  3. 提前关闭。
  4. 在一个已关闭的socket上收到数据。

注意:服务器崩溃后的重启是不会收到RST的。

URG标志位:紧急指针标志位,和16位紧急指针相关。

16位校验和:CRC校验,校验整个TCP报文(报头+数据)。


TCP是以段为单位发送数据

由于TCP是以段为单位进行发送数据,MSS(Maximum Segment Size)为该段的最大消息长度。最理想的情况下,最大消息长度正好是IP中不会被分片处理的最大数据长度(IP是否分片又取决于底层MAC帧的最大传输长度(MTU),默认情况下MTU = 1500字节)。

通信双方在建立连接时进行协商MSS值的大小,也就是在发送SYN时会在TCP头部写入自己能支持的MSS值,通信双方选择最小的MSS值作为双方通信最终的MSS,MSS的值就是在TCP首部的40字节变长选项中。下图为协商MSS大小的示意图:

 


超时重传

如果发送端在一定时间内没有等到确认应答的数据包,发送端就认为该数据包丢失,此时需要重传,可以看到,这也是TCP可靠性的一种体现。

发送端认为数据包的丢失有两种情况

1、数据包没有到达接收端。

可能因为网络拥堵等原因,数据包未到达对方,接收端等待一个特定的时间后未收到确认应答,就会将数据进行重发。 

特定的时间

这个时间的长短其实和网络环境相关。

等待时间太长重传的效率变低,等待时间太短频繁的发送数据包会造成网络负担变大。

重发超时的时间 > 数据包的往返时间(RTT)+ 偏差。

在Linux中,超时以500ms为一个单位进行控制,每次判定超时重发的超时时间都是500ms的整数倍。如果重发一次后仍得不到应答,则下一次的重发时间将是2倍、4倍的指数函数延长。当然这个时间也不是无限的延长,在重发一定次数后仍没有任何应答返回,发送端判定对方发生异常,强制关闭连接,并通知上层通信异常终止。

2、数据包到达了接收端,但发送端没有收到确认应答。

这种情况就是接收端会受到重复的数据包,那么对于重复的数据包该如何处理呢?

因为存在序号,出现相同的序号说明之前有收到过同样的包,则丢弃相同序号的数据包。


TCP三次握手

TCP是面向连接的,所以在双方正式通信之前得先建立连接。建立连接的过程如下图所示:

 

上图就是经典的三次握手的过程,站在实际编程的角度来看,双方都得先创建套接字,服务器还需要绑定ip地址和端口号,并将套接字变为监听套接字。

 一旦客户端调用connect函数,就会发出建立连接的请求,接下来的任务交给操作系统完成。

首先客户端发送SYN,状态为SYN_SENT状态。

当服务器收到SYN时,服务器会进入SYN_RCVD状态。

服务器接下来发送SYN+ACK,当客户端收到SYN+ACK时会立即进入ESTABLISHED状态,并发送ACK。

当服务器收到ACK后也进入ESTABLISHED状态,三次握手建立连接结束。

注意:accept发生在三次握手之后,三次握手的过程其实是监听就完成了,accept只是为了取走连接。

为什么是三次握手?

三次握手服务器和客户端至少有一次收和一次发。这样可以测量信道的好坏

1、可以验证TCP的全双工(保证互相都能正常的通信)

双方都要发送数据,且双方都可以收到对方的数据,这样才能确保互相可以正常的通信。

一次握手和两次握手就存在至少有一方的信道状态是不确定的。

一次握手的问题

一次握手客户端向服务器发送请求就直接建立连接,这个过程和UDP没什么区别。根本无法知道服务器是否成功建立连接。


两次握手的问题

客户端发送SYN,服务器返回SYN+ACK,客户端收到SYN+ACK,连接建立,此时只知道客户端到服务器的信道是通畅的,但是服务器到客户端的信道是否通畅。其实和一次握手没有太大的区别

一次握手和两次握手都容易造成SYN洪水攻击。

2、不让服务器建立连接出现误判的情况

在三次握手过程中,这三次的报文都有可能丢失,但是最后一次的报文的丢失是影响最大的,原因是,最后一次客户端向服务器发送ACK之后,客户端这边默认是连接已经建立(在操作系统层面就是一批数据结构的创建和文件描述符的资源等)。

如果是四次握手,让最后一次握手在服务器这里,报文的是否丢失都会默认以为连接建立好,增加了服务器的开销,很明显,我们不想增加服务器的开销,毕竟服务器不是未一个客户端所服务的。

五次握手、七次握手等等也可以建立连接,但不是最优解。所以说三次握手是最优解

绝对可靠性

网络通信不存在绝对可靠性,因为永远最近的一个ACK不可靠,不可能无限ACK下去。

相对可靠性

当client发送数据给server,server应答ACK,这个ACK是确保上一个数据的准确发出,如果client不管是什么原因没有收到ACK,client会重新发送一次数据给server(超时重传)。


TCP的四次挥手

通信双方都可以率先关闭连接,以客户端首先关闭连接为例。

客户端在应用层调用close函数关闭socket套接字,之后操作系统会发送FIN给服务器。

客户端这边发送FIN后进入FIN_WAIT_1状态,服务器收到FIN后进入CLOSE_WAIT状态,并发送ACK给客户端。,当客户端收到服务器返回的ACK时,两次挥手的过程完成,客户端的状态变为FIN_WAIT_2,客户端到服务器的通信信道关闭。

服务器这边也发起close关闭连接,发送FIN,服务器进入LAST_ACK状态。当客户端收到服务器的FIN数据包后进入TIME_WAIT状态,并返回ACK。服务器正常收到ACK,剩下两次挥手完成,服务器到客户端的信道也关闭。

两个状态:CLOSE_WAITTIME_WAIT

如果服务器存在大量的CLOSE_WAIT状态的连接,就是说明服务器没有close掉对应的文件描述符,文件描述符也是一种资源,会造成系统资源的浪费。

TIME_WAIT状态的作用是避免服务器没有收到最后一个ACK,或者说最后一个ACK丢失,则服务器不会进入CLOSED状态。

由于四次挥手的过程也是数据的通信,每一次都有可能会丢包,如果是最后一次ACK的包丢了,沿用上面的例子,如果不设置TIME_WAIT状态,客户端直接进入CLOSED状态,则不会进行超时重传的机制。导致服务器这边一直在超时重传FIN,迟迟无法进入CLOSED状态。

所以TIME_WAIT状态就是为了降低失败的概率,客户端会等待一段时间,如果没等到FIN就会认为服务器已经收到了ACK,接下来客户端就会断开连接,如果再次收到FIN,则客户端再次发送ACK。

TIME_WAIT等待的时间2MSL(MSL报文最大的生存时间,超过这个时间报文就会被丢弃,通常为30s,1min,2min等)。

除此之外TIME_WAIT还可以保证历史数据在网络上消散,以及新的连接的到来不受之前延迟报文的影响。

由于上述例子是以客户端关闭连接为例,如果服务器主动关闭连接,也会进入TIME_WAIT状态,所以,主动断开连接的一方要进入TIME_WAIT状态。


滑动窗口

如果每次只发一个段的数据,然后等待确认应答的到来,收到确认应答后在发送一个数据,这样就很明显是一个乒乓操作,效率低,网络的吞吐量差。

为了解决这个问题,TCP引入滑动窗口的方式

图中所示的窗口大小为4个段,共4000字节。

这样就可以实现无需等待上一个段的数据的确认应答继续发送下一个段的数据(注意无需等待不是不需要确认应答,只是我可以先不等待上一个的确认应答,先把我这个窗口内的数据发送完毕,进而以更大的单位进行确认)。

所以说这种滑动窗口的机制就是边发送边确认应答 ,这样也可以充分利用缓冲区,通过对多个段同时进行确认应答功能。

如果此时客户端收到了确认序号为2001的,就表示 2001以前的数据都正常的到达服务器了,此时1001这个确认序号到没到达不重要了,窗口就需要向右移动两段。发送的数据从4000改变最多可以发送到6000这里。

滑动窗口的大小是动态改变的,取决于TCP报头16位窗口大小字段,对方所给出的窗口的大小和拥塞窗口大小二者之间的最小值


快速重传

上述的滑动窗口的方式如果有丢包的情况该怎么办?

如果是向上面这种确认应答丢了,即使有少部分的确认应答丢了也不会进行数据的重发,因为可以通过下一个确认应答来对前面的数据进行确认。

例如客户端收到了4001的确认序号,表示4001以前的数据都收到了,即使丢了3001和1001的确认序号也不影响接下来的数据的传输。

如果是发送端的数据丢失了,则接收端会连续的对之前的数据进行确认应答,直到重新收到丢失的数据。与此同时发送端如果收到连续3次同一个确认应答,就会将其所对应的数据进行重发。这种机制比超时重传更加的高校,所以叫做快速重传

既然有快速重传为什么还要有超时重传?

超时重传是兜底,如果一个窗口内所有的ACK都丢了或者是所有的数据都丢失,则会触发超时重传。


延迟应答

由于如果收到发送端的数据,立刻返回一个ACK,可能会返回一个较小的窗口,因为缓冲区的数据还不一定来得及处理或者只处理了一小部分。

延迟应答的目的是提高网络利用率,通俗一点来说就是等待接收方处理一会数据,让下次接收方返回的窗口大小大一点,窗口大小越大网络吞吐量越大。

延迟应答麻烦的地方就在于延迟的时间的控制,时间小了窗口小,时间长了可能会触发发送端的超时重传。

捎带应答

在一个TCP包中既发送数据也发送确认应答的一种机制。接收方接收到数据之后先等数据处理完生成返回的数据以后在连同确认应答一起发送。可以看到这也需要一种延迟的策略。也就是说没有启用延迟应答也就无法实现捎带应答。


流量控制

TCP根据接收端的处理能力,来决定发送端的发送速度,这个机制就叫流量控制。

流量控制有两个策略

1、窗口更新通知

每次确认应答的时候,服务器都会携带窗口信息,发送端主机会根据窗口大小进行调整。

2、窗口探测

如果窗口更新通知丢失在中途丢失,发送端迟迟收不到怎么办?

发送端主机会时不时的发送一个窗口探测数据段,此数据段仅包含一个字节来获取窗口大小信息。


拥塞控制

根据网络的环境控制窗口的大小,发送端调节所要发送数据的量,这里会定义一个拥塞窗口

慢启动

为了防止在通信一开始就发送大量的数据,引入慢启动的概念。

在慢启动刚开始的时候,拥塞窗口为1个数据段,拥塞窗口的增长速度在慢启动的阈值以下时是呈指数级增长

慢启动的阈值在刚开始启动时,等于窗口最大值;当超过阈值时,拥塞窗口的大小呈线性增长

每次发送数据包的时候, 将拥塞窗口和接收端主机反馈的窗口大小做比较, 取较小的值作为实际发送窗口

用上图的例子,TCP通信开始时,拥塞窗口大小为1,逐渐指数增长,增长到阈值后开始线性增长。当网络拥塞时(超时重发、大量的丢包),慢启动阈值会变成原来的一半,同时拥塞窗口变为1。所对应的是图中第13轮


TCP总结

可靠性的体现:校验和、序列号、确认应答、超时重发、流量控制、拥塞控制。

有效性的体现:滑动窗口、快速重传、延迟应答、捎带应答。

参考文献:图解TCP_IP(这本书讲的还是很通俗易懂的)。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值