猿创征文|网络原理——UDP/TCP协议

简介: 本文主要介绍在TCP/IP的五层协议模型中,传输层的最常见的两个协议——UDP协议与TCP协议。TCP提供可靠的通信传输,而UDP则常被用于让广播和细节控制交给应用的通信传输。下边我们来一起具体了解这两个协议。

1.UDP协议


UDP的特点为无连接、不可靠传输、面向数据报、全双工。


  • 无连接:不需要进行连接就可以发送数据,通过UDP协议可以完成一个主机同时向多个主机发送消息。
  • 不可靠传输:发送端并不能知道接收端是否收到了消息。
  • 面向数据报:以数据包为单位进行传输。
  • 全双工:A和B可以同时向对方发送接收数据


UDP的报文格式如下图:


微信图片_20230111135257.png

上图为教科书上呈现的格式,其实际格式如下图:


微信图片_20230111135253.png

以下为对其报文中的一些组成的解释:


  • 源端口号:发送发的端口号
  • 目标端口号:接收方的端口号
  • 包长度(报文长度):表示一个UDP数据包的大小,单位为字节
  • 校验和:用来验证网络传输的数据是否正确


在上述UDP报文中,报文长度用两字节存储,其范围为0~65535,如果有一个较大的数据报需要传输时,包长度就超出了最大范围,无法表示一个比较大的数据报,于是就有了TCP这种协议来更好的处理这种情况。


2.TCP协议


2.1 TCP头部格式


TCP头部格式如下图:


微信图片_20230111135249.png

源端口号、目的端口号、校验和:其作用与UDP中的作用相同


序列号:在建立连接时由计算机生成的随机数作为其初始值,通过SYN包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用于解决网络包乱序问题。


确认应答号:指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后,可以认为在这个序号以前的数据都已经被正常接收。用于解决不丢包的问题。


首部长度:表示TCP报文长度,一共4比特,能表示0-15,单位为4字节,也就是说能表示TCP报头长度为0-60字节,如果不够用,还有后边的保留位。


控制位(TCP报文的核心字段):


微信图片_20230111135246.png

  • ACK:该位为1时,「确认应答」的字段变为有效,TCP规定除了最初建立连接时的SYN包之外该为必须设置为1.
  • RST:该位为1时,表示TCP连接中出现异常必须强制断开连接。
  • SYN:该位为1时,表示希望建立连接,并在其「序列号」的字段进行序列号初始值的设定。
  • FIN:该位为1时,表示今后不会再发送数据,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换FIN位为1的TCP段。


其余报头中暂未提及的部分在文章后续慢慢介绍。


TCP的特点是有连接,可靠传输,面向字节流,全双工。


  • 有连接:⼀定是「⼀对⼀」才能连接
  • 可靠传输:发送端能够知道接收端是否收到了消息
  • 面向字节流:以字节流的方式进行传输,可以自行定义发送的字节多少,比较灵活
  • 全双工:A和B可以同时向对方发送接收数据


在TCP的这些核心机制中,除了可靠传输之外,其他性质都可以在代码中体现出来,虽然可靠传输不能直接在代码中体现出来,但是这个却是TCP最核心的机制,下边我们就来了解TCP都是通过怎样的方式来完成可靠传输的。


2.2 TCP可靠性实现机制


2.2.1 确认应答


该机制为保证可靠传输的核心机制。


在发送方发出去数据之后,在接受方接收到消息后返回给发送方一个应答报文(ACK) 来表示自己已经收到了。


下边我们来通过我请女神吃牛排的例子来更好的理解这个问题:


微信图片_20230111135241.png

但如果发了多条消息,可能就会出现后发先至的情况:


微信图片_20230111135238.png

如果出现这种情况,将会引起不必要的误会,我们可以通过对消息进行编号的方法来解决上述问题:


微信图片_20230111135235.png

上述的序号与确认序号便对应TCP报头中的序列号与确认应答号,通过编号的方式来针对哪个消息进行确认应答。


微信图片_20230111135232.png

在实际的TCP传输中,并不是按“消息条数”来进行编号的,而是按照字节来进行编号


微信图片_20230111135229.png

A给B发送了1000个字节,序号为1-1000,那么B给A返回的应答报文(ACK)就会带有一个确认序号——1001(表示小于1001的数据都被主机B收到了,接下来主机A应该从1001这个序号开始,往后进行传递)


2.2.2 超时重传


在网络一切正常的情况下,上述确认应答可以正常完成,但如果由于网络问题出现了丢包的问题,超时重传机制就要其效果了(超时重传是确认应答的补充)


在一个数据发送出去之后,一段时间过去并没有收到应答报文,这时发送方将会重新发送数据(当然不会无限制的重发,如果由于网络问题将会停止重发)。


触发重传的情况有以下两种:

一种是数据丢了,那么发送方在等待一段时间后重发就可以了。


微信图片_20230111135225.png

另一种情况是ACK丢了,对方虽然收到了消息,但是我却收不到ACK,对于发送方的我来说,并不知道是哪种原因导致我没有收到ACK,所以我以最坏情况打算,就认为是对方没有收到数据,在一段时间过后我会重发一次。但这样对方实则会收到重复的消息,在TCP内部会进行去重操作,并返回一个和之前相同的ACK。


微信图片_20230111135222.png

图解TCP/IP 超时重传示图:


微信图片_20230111135219.png

2.2.3 连接管理(三次握手、四次挥手)


2.2.3.1 三次握手


TCP是面向连接的协议,所以使用TCP前必须先建立连接,而建立连接是通过三次握手来进行的。


微信图片_20230111135215.png

客户端和服务器之间通过三次交互,完成了建立的过程,“握手”是一个形象的比喻。

在上图中的两侧也表明了TCP的状态,我们需要主要了解的如下:

LISTEN:表示服务器启动成功,端口绑定成功,随时可以有客户端来建立连接(手机开机,信号良好,随时可以有人给我打电话)

ESTABLISHED:表示客户端已经连接成功,随时可以进行通信了(有人给我打电话我接听了,接下来就可以说话了)


通过三次握手,可以检查当前网络的情况是否满足可靠传输的基本条件,例如我们在给人打电话时,打通电话后第一句是“喂,可以听到吗”,如果接收方听到了会回一句“听到了,你能听到我说话吗”,这一句回复就说明了我的麦克风和喇叭都是正常的,我听到后会回复“可以听到”,这一句回复验证了接收方的麦克风和喇叭是正常的,这个过程就是在验证通信双发的发送和接收能力是否都正常。


那如果两次可以吗?

两次意味着缺少最后一次,此时客户端这边发送接收能力是正常的,但是服务器这边是残缺的,服务器不知道自己的发送能力是否正常,也不知道客户端的接收能力是否正常,所以第三次握手不可少。


如果四次可以吗?


微信图片_20230111135209.png

四次意味着SYN和ACK需要分开传输,降低了效率


2.2.3.2 四次挥手


通过三次握手,就让客户端和服务器之间建立好了连接,建立好连接后,就需要占用一定的系统资源来保存连接相关的信息,如果连接断开,此时之前保存的连接信息就没有意义了,对应的空间也就可以释放了。


微信图片_20230111135206.png

双方各自向对方发送了FIN(结束报文段)请求,并且各自给对方一个ACK确认报文。


在三次握手中,一定是客户端主动发起的,但在四次挥手中,可能是客户端主动发起,也可能是服务器主动发起。


三次握手中,中间两次可以合并,但是四次挥手的中间两次有时候合并不了(有时候是可以合并的),不能合并的原因在于B发送ACK和B发送FIN的时机不同,B给A发的ACK是由内核负责的,而B给A发的FIN是用户代码负责的(代码中调用了socket.close()方法),如果这两个操作之间的时间差比较大就不能合并了,如果时间差比较小是又可能合并的(延时应答和捎带应答,在后边详细解释)。


我们也来认识四次挥手中两个重要的状态:


CLOSE_WAIT : 四次挥手挥了两次之后出现的状态,这个状态就是在等待代码中调用socket.close()方法,来进行后续的挥手过程

TIME_WAIT :谁主动发起FIN,谁就会进入TIME_WAIT状态。其是为了给最后一次ACK提供重传机会。

由于最后一次主动方发送ACK后可能丢包,如果丢包了被动方就会以最坏情况,重传FIN(超时重传),所以主动方需要预留一段时间来等待被动方重发FIN,预留的时间为2MSL,MSL表示报文最大生存时间。如果在等待过程中没有接收到FIN,服务器就与客户端断开连接了。


2.2.4 滑动窗口


TCP虽然可靠性是最高的机制,但是TCP也会尽可能的提高传输效率


由于确认应答机制的存在,导致了当前每次执行一次发送操作,都需要等待上个ACK的到达,大量的时间都花在了等待ACK上了。


微信图片_20230111135202.png

滑动窗口的本质就是在“批量的发送数据”,一次发送一波数据,然后一起等一波ACK


微信图片_20230111135159.png

比如客户端一次发送了4组数据,然后等ACK的到达(这样一份的时间就等待了多份ACK,把多份ACK的时间压缩成一份了),如果一次批量发送数据为N,统一等待一波,此时这里的N称为“窗口大小”,“滑动”的意思是,并不用把N组数据的ACK都等到了才继续往下发送,而是收到一个ACK就往下发送一组。随着ACK接连到来,接连发送新的数据,此时这个“窗口”,就在逐渐往后“滑动”。


微信图片_20230111135156.png

但如果在滑动窗口的背景下出现了丢包问题,该如何进行重传呢?

丢包分为两种情况:

一种是ACK丢了,这种情况不需要处理,这是因为ACK确认序号的含义是该序号以前的数据都已经收到了,也就是说在发送方收到5001的时候,意味着1-5000的数据都确认收到了,及时ACK(确认应答号)3001、4001都丢包了,只要收到5001,就涵盖了3001和4001表达的信息。


微信图片_20230111135153.png

另一种情况是数据丢了,这就必须要进行处理了,如下图,由于1001-2000这个数据丢了,B就在反复索要1001这个确认应答号,即使A已经在给B发后边的数据了,但仍然再索要1001的确认应答报文,当索要若干次以后,A就会触发重传。


微信图片_20230111135149.png

在A重传1001-2000之前,B的接收缓冲区如下图所示,数据一直在接收但是有缺口,在A完成重传后把接口给补上就行了(其他已经到了的数据就不必再进行重传),接下来B就向A索要7001开始的数据就行,这种机制也被称为高速重发控制。


微信图片_20230111135146.png


2.2.5 流量控制


在滑动窗口中,窗口越大,传输效率就越高,但是我们不仅要考虑发送方的传输速度,还需要考虑接收方的处理速度。

流量控制的关键,就是能够衡量接收方的处理速度,根据接收方接收缓冲区的剩余空间大小,来衡量当前的处理能力。

如果剩余空间比较大,就认为接收方的处理能力比较强,就可以让A发的快点

如果剩余空间比较小,就认为接收方的处理能力比较弱,就可以让A发的慢点

在TCP头部中,有窗口大小一栏,接收方在ACK报文中通过窗口大小来告知发送方剩余空间的大小。


微信图片_20230111135143.png

《图解TCP/IP》流控制示意图:


微信图片_20230111135139.png

其中的窗口探测报文中不含任何数据,只是为了触发ACK,来知道当前窗口的大小是多少。


2.2.6 拥塞控制


也是滑动窗口的延申,用于限制滑动窗口发送的速率

拥塞控制衡量的是发送方到接收方的链路之间的拥堵情况(处理能力)


微信图片_20230111135136.png

A能够发多快,不光取决于B的处理能力,也取决于中间链路的处理能力。

A一开始以一个比较小的窗口来发送数据,如果数据很流畅的就到达了,那就逐渐加大窗口大小;如果加大到一定程度之后,出现了丢包的情况(丢包意味着通信链路出现拥堵了),这个时候就需要减小窗口。

通过反复的增大/减小窗口,就逐渐摸索到了一个比较合适的范围,拥塞窗口就在这个范围中不断变化,达到“动态平衡”。


拥塞窗口的具体变化如下图:


微信图片_20230111135133.png

2.2.7 延时应答


延时应答相当于流量控制的延申,流量控制的目的是为了使发送方不要发送的太快,而延时应答在此基础上,希望窗口能更大一些。


在发送方询问接收方窗口大小的时候,不立即做出回答,而是稍等一下再回答,这样接收方又可以多处理一部分数据,窗口就又大一些,这个操作就是在有限的情况下,又尽可能的提高了一点传输速度。


2.2.8 捎带应答


捎带应答又是延时应答的延申。

因为延迟应答的存在,导致接受方的ACK不一定是即时返回的,如果延时应答导致ACK的返回时机和应用代码中返回的响应时机重合了,就可以把这个ACK和响应数据合二为一(就像四次挥手中第二三次挥手过程,ACK和FIN就有可能同一时机返回)


2.2.9 粘包问题


TCP粘包粘的是应用层数据包(不仅是TCP存在粘包问题,其他面向字节流的机制比如读文件,也存在粘包问题)

在TCP接受缓冲区中,若干个应用层数据包混在一起就分不出来谁是谁了,如果想要解决这个问题就需要在应用层中加入包的边界,比如:约定每个包的结尾以;结尾。


2.2.10 TCP异常处理


1.进程终止


在进程毫无准备的情况下,突然结束进程。


微信图片_20230111135125.png

TCP连接是通过socket来建立的,socket本质上是进程打开的一个文件,文件其实就存在于进程PCB里的文件描述符表

每次打开一个文件(包括socket),都会在文件描述符表里增加一项

每次关闭一个文都会在文件描述符表里删除一项

如果直接杀死进程,PCB也就没有了,里面的文件描述符表也就没有了,此处文件相当于“自动关闭”了,这个过程和手动调用socket.close()一样,都会触发四次挥手


2.机器关机


如果按照操作系统约定的正常流程关机,会让操作系统杀死所有进程然后关机,四次挥手的过程依旧会执行。


3.机器断电/网线断开


当电源或者网线直接断开时,操作系统根本来不及反应,那么四次挥手也无法执行


当接收方断电或者断网时,发送方会尝试重新连接,重连失败一定次数,就会放弃连接。

当发送方断电或者断网时,接收方会发送一个探测报文,触发发送方的ACK,如果没有反应,接收方就认为发送方出现了问题。


3.TCP/UDP总结


如果开发对可靠性有一定要求时,使用TCP(日常开发中的大多数情况都是基于TCP);如果开发对可靠性要求不高,对于效率要求更高,使用UDP(机房内部的主机之间的通信)

UDP如何实现可靠性呢?其实UDP实现可靠性是TCP的复刻,只是按照相同的思路在应用层完成就可以了。


相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
20小时前
|
网络协议 程序员 API
LabVIEWCompactRIO 开发指南19 原始以太网(TCP/UDP)
LabVIEWCompactRIO 开发指南19 原始以太网(TCP/UDP)
|
2天前
|
网络协议 程序员 网络性能优化
【网络原理】TCP 协议中比较重要的一些特性(三)
【网络原理】TCP 协议中比较重要的一些特性(三)
10 0
|
2天前
|
缓存 网络协议
【网络原理】TCP 协议中比较重要的一些特性(二)
【网络原理】TCP 协议中比较重要的一些特性(二)
10 0
|
2天前
|
网络协议
【网络原理】TCP 协议中比较重要的一些特性(一)
【网络原理】TCP 协议中比较重要的一些特性(一)
8 0
|
3天前
|
XML 网络协议 算法
UDP/TCP协议特点
UDP/TCP协议特点
21 0
|
4天前
|
网络协议 Java Linux
【探索Linux】P.29(网络编程套接字 —— 简单的TCP网络程序模拟实现)
【探索Linux】P.29(网络编程套接字 —— 简单的TCP网络程序模拟实现)
11 0
|
13天前
|
监控 安全 Linux
【专栏】Linux中六个常用的网络命令:ping、traceroute、netstat、nmap、ifconfig和ip
【4月更文挑战第28天】本文介绍了Linux中六个常用的网络命令:ping、traceroute、netstat、nmap、ifconfig和ip,以及它们在测试网络连通性、追踪路由、查看网络状态、安全扫描和接口配置等场景的应用。通过学习和运用这些命令,系统管理员和网络爱好者能更有效地诊断和管理网络问题,确保网络稳定运行。
|
3天前
|
域名解析 网络协议 Linux
linux网络配置详解
linux网络配置详解
12 0
|
4天前
|
存储 网络协议 算法
【探索Linux】P.28(网络编程套接字 —— 简单的UDP网络程序模拟实现)
【探索Linux】P.28(网络编程套接字 —— 简单的UDP网络程序模拟实现)
11 0
|
4天前
|
网络协议 算法 Linux
【探索Linux】P.27(网络编程套接字 —— UDP协议介绍 | TCP协议介绍 | UDP 和 TCP 的异同)
【探索Linux】P.27(网络编程套接字 —— UDP协议介绍 | TCP协议介绍 | UDP 和 TCP 的异同)
14 0