【JavaSE】【网络原理】UDP和TCP原理
目录
- 一、UDP协议
- 二、TCP协议
- 2.1 TCP结构
- 2.2 TCP十大核心机制
- 2.2.1 确认应答
- 2.2.2 超时重传
- 2.2.3 连接管理
- 2.2.3.1 三次握手建立连接
- 2.2.3.2 四次挥手断开连接
- 2.2.4 滑动窗口
- 2.2.5 流量控制
- 2.2.6 拥塞控制
- 2.2.7 延时应答
- 2.2.8 捎带应答
- 2.2.9 面向字节流
- 2.2.10 异常情况处理
- 三、TCP、UDP对比

一、UDP协议
UDP在前面套接字编程介绍了特点是:
无连接、不可靠传输、面向数据报、全双工。
UDP协议格式:
- 16位UDP⻓度,表⽰整个数据报 (UDP⾸部+UDP数据) 的最⼤⻓度,0 - 65535,也就64KB;
- 16位UDP校验和:如果校验和出错,就会直接丢弃;
校验和的作用:
- 防止传输过程出现比特翻转(比特翻转就是指:数据受到外界干扰,0变1,1变0)
发送之前,先计算一个校验和,把真个数据报的数据都代入
把数据 和 校验和 一起发送给对端
接收方收到之后重新计算一下校验和,和收到的校验和进行对比(UDP发现校验和不一致,就会直接丢弃)
UDP的校验和使用了CRC方式来进行校验(循环冗余校验)
把每个字节(除了校验和位置的部分之外),都当做整数进行累加.溢出也没关系,继续加
最终得到结果CRC校验和
传输到对端时,数据如果出现错误了,对端再次计算的校验和,就会和第一个校验和不一样了
校验和相同,原始数据可能相同(原始数据不同发生的概率非常小)。
校验和不同,原始数据一定不同。
这样的机制虽然也有错,因为一个数据和对应的数据不是唯一的,但是这种是小概率事件。
二、TCP协议
2.1 TCP结构
TCP在前面套接字编程介绍了特点是:
有连接、可靠传输、面向字节流、全双工。
TCP格式:
- 4位首部长度:表⽰该TCP头部有多少个32位bit (有多少个4字节);所以TCP头部最⼤⻓度是15 * 4 = 60 字节
- 选项:选项就是确定TCP长度是可变的,固定长度是20字节,选项最多增加40字节
- 保留位:UDP长度不够时,不能扩展,而保留位就是TCP预留解决这种问题的。
- 6个标志位:
-
- URG:紧急指针(相当于“插队”,跳过前面数据,从指定序号开始)是否有效
-
- ACK:确认号是否有效
-
- PSH:催促标志位,提⽰接收端应⽤程序⽴刻从TCP缓冲区把数据读⾛
-
- PST:对⽅要求重新建⽴连接;我们把携带RST标识的称为复位报⽂段
-
- SYN:请求建⽴连接;我们把携带SYN标识的称为同步报⽂段
-
- FIN:通知对⽅,本端要关闭了,我们称携带FIN标识的为结束报⽂段
- 16位校验和:校验数据是否出现错误
- 16位紧急指针:标识哪部分数据是紧急数据
2.2 TCP十大核心机制
2.2.1 确认应答
保证可靠性:那就肯定需要,发送放知道接收方是否接收到请求,接收方返回一个“应答报文(acknowledge ,ack)”
如果有这种情况:后发先至
网上做题是答案是对应题目的,但是如果你先写的第一题答案,后写的第二题答案,由于传输问题,导致第二题答案先到。那么如果没有题号对应的话,那么就可能填在第一题去了。所以TCP也引入的类似题号作用的东西:序列号
TCP将每个字节的数据都进⾏了编号。即为序列号。
每⼀个ACK都带有对应的确认序列号,意思是告诉发送者,该确认序号前的数据都已经收到;下⼀次你从哪⾥开始发。
2.2.2 超时重传
超时重传是为了应对丢包问题。
丢包:数据无法到达指定位置。
丢包两个原因:假如主机A发送数据给主机B
- 主机A发送的数据,由于各种原因,没能到达主机B,造成丢包
- 主句B返回的应答数据,由于各种原因,没能到达主机A,造成丢包
TCP就引入超时时间(TCP中判定超时的时间阈值,不是固定值,动态变化),来应对丢包情况,
当超出超时时间,还没有接收到应答报文,那么就是出现丢包(无论哪种原因造成),那么都会重新发送这条数据。
超时时间的动态变化机制:
TCP为了保证⽆论在任何环境下都能⽐较⾼性能的通信,因此会动态计算这个最⼤超时时间。
- Linux中(BSD Unix和Windows也是如此),超时以500ms为⼀个单位进⾏控制, 每次判定超时重发的
超时时间都是500ms的整数倍.- 如果重发⼀次之后, 仍然得不到应答, 等待 2*500ms 后再进⾏重传.
- 如果仍然得不到应答, 等待 4*500ms 进⾏重传. 依次类推, 以指数形式递增.
- 累计到⼀定的重传次数, TCP认为⽹络或者对端主机出现异常, 强制关闭连接.
确认应答和超时重传是确认TCP可靠传输的最核心机制。
2.2.3 连接管理
TCP中连接是逻辑上的连接,都保留对端的信息,不是物理上的连接。
两个主机间的连接管理,TCP通过三次握手机制建立连接,四次挥手断开连接。
2.2.3.1 三次握手建立连接
过程简述:主机A与主机B通信
- 主机A先发一个状态码为syn的报文给主机B(相当于我给你打电话,你接通后,我先说一个喂)
- 主机B接收到主机A发的报文后,也要发一个状态码为ack的应答报文,还要发送一个syn报文,这两个报文可以一起发送。(这就相当于打电话,你听到了我说喂,你回一个干嘛)
- 主机A收到主机B的报文后,要发送一个状态码为ack的应答报文。(就相当于打电话,我知道你那边听筒和麦克风正常,我就开始说事了,你听到我说事,也就知道我设备没问题,但是在TCP中要应答报文,让主机B知道,然后才是发送数据)
syn和ack报文简述:
- syn报文,就是通知对端我要和你建立连接了,这里面包含了发送端的信息,让对端保存好
- ack报文,就是通知对端你发的报文,我收到了,将信息记录好了。
三次握手简图:
三次握手机制好处:
- 三次握手,相当于“投石问路”,初步探索一下网络通信链路是不是畅通的
- 验证通信双方的发送和接收能力是不是正常的。
- 三次握手过程中,是可以协商一些关键数据的,比如通信的初始序号
2.2.3.2 四次挥手断开连接
过程简述:主机A与主机B通信
- 主机A先发一个状态码为FIN的报文给主机B(相当于我给你打电话,我要挂电话了,我说我要挂电话了,你还有事吗)
- 主机B接收到主机A发的报文后,也要发一个状态码为ack的应答报文,(这就相当于打电话,你听到了我说要挂电话了)
- 还要发送一个FIN报文。(这就相当于打电话,你听到了我说要挂电话了,你回一个ok)
- 主机A收到主机B的报文后,要发送一个状态码为ack的应答报文。(就相当于打电话,我挂电话)
在四次挥手时:接收端发送的FIN和ACK报文如能合并。
接收端发送的FIN和ACK报文,只有在延时应答机制下才能合并。而其他时候不能合并。因为ACK的报文是操作系统内核发的,而FIN报文是程序猿代码调用到Socket的close方法才发送的。
四次握手简图:
三次握手与四次挥手的丢包问题:
三次握手无论哪个报文发生丢包,触发超时重传就可以解决。
四次挥手中在除了最后发送端(主机A)的ACK报文外,其它报文发生丢包问题,触发超时重传就可以解决。
当发送端(主机A)接收到了FIN,直接发送ACK,同时释放这次资源,那么如果ACK丢包,主机B重传FIN后,主机A都不认识了。这是就引入一个TIME-WAIT状态(在接收到了FIN后等一定时间),再释放资源。
CLOSE-WAIT:
⼀般⽽⾔,对于服务器上出现⼤量的 CLOSE_WAIT 状态, 原因就是服务器没有正确的关闭 socket, 导致四次挥⼿没有正确完成. 这是⼀个 BUG. 只需要加上对应的 close 即可解决问题.
三次握手和四次挥手的详图(出自《图解TCP/IP》)
2.2.4 滑动窗口
滑动窗口:
像在发送数据报的时候,我们发一条等待对方接收一条返回一条应答报文,那么和发一堆再进入等待状态相比,明显后者的效率更高。
滑动窗口就是指第二种发数据方式。
滑动窗口机制解析:
- 窗口大小:就是指无需等待的数据报数量,也就是第一次可以发送的最大值。
- 进出数据:滑动窗口中的数据,接收到了哪个确认序列号,就将滑动窗口的头移动到对应的确认序列号的数据地方
- 操作系统内核为了维护这个滑动窗⼝, 需要开辟 发送缓冲区 来记录当前还有哪些数据没有应答; 只有确认应答过的数据, 才能从缓冲区删掉;
- 滑动窗口的大小要适量,过大会影响TCP的可靠性,过小对效率提升没啥作用。
滑动窗口中的丢包问题:
-
数据报已经抵达, ACK丢了。
这种情况,不用任何处理,因为后面到达的ACK的确认序号就包含了,前面的数据都接收到了的意思。
-
数据报丢了
快速重传:在滑动窗口下的变种机制。
2.1. 当某⼀段报⽂段丢失之后, 发送端会⼀直收到 1001 这样的ACK, 就像是在提醒发送端 “我想要的是1001” ⼀样;
2.2. 如果发送端主机连续多次都收到了同样⼀个 “1001” 这样的应答, 就会将对应的数据 1001 - 2000 重新发送;
2.3. 这个时候接收端收到了 1001 之后, 再次返回的ACK就是7001了(因为2001 - 7000)接收端其实之前就
已经收到了, 被放到了接收端操作系统内核的接收缓冲区中;
2.2.5 流量控制
流量控制:
接收端处理数据的速度是有限的. 如果发送端发的太快, 导致接收端的缓冲区被打满(就像小学数学小明给泳池一边放水一边蓄水一样), 这个时候如果发送端继续发送, 就会造成丢包, 继⽽引起丢包重传等等⼀系列连锁反应.
因此TCP⽀持根据接收端的处理能⼒, 来决定发送端的发送速度. 这个机制就叫做流量控制(Flow Control);
如何实现流量控制:
- 接收端将自己的接收缓冲区剩余的容量,通过TCP首部的“十六位窗口大小”字段,通过ACK发给发送端,发送端根据这个值来设置滑动窗口大小,来实现流量控制。
特点:
- 16位数字最⼤表⽰65535,但是TCP窗⼝最⼤却不是65535字节么。实际上,TCP⾸部40字节选项中还包含了⼀个窗⼝扩⼤因⼦M,实际窗⼝⼤⼩是 窗⼝字段的值左移 M 位;
- 如果接收端缓冲区满了,就会将窗⼝置为0;这时发送⽅不再发送数据,但是需要定期发送⼀个窗⼝探测数据段,使接收端把窗⼝⼤⼩告诉发送端。
流程解释图:
2.2.6 拥塞控制
拥塞控制:依据通信链路的转发能力,进行限制。
找拥塞控制的滑动窗口的大小:
我们前面的流量控制的滑动窗口的大小,直接是TCP首部字段带的。但是我们通信链路没这个功能,我们就将通信链路当一个整体,先按照小的窗口发着,一直加大窗口,当窗口过大,发生丢包就减小窗口到较小值,再次执行前面操作,又增大窗口(面多加水,水多加面),让窗口大小一直处于丢包临界值动态平衡。
图解:
-
-
慢启动:初始的小窗口大小
-
ssthresh初始值:预设的窗口大小
-
过程解析:慢启动 -> 指数增长 -> 线性增长 -> 丢包,窗口变回较小值
滑动窗口的最终大小取决于拥塞控制和流量控制的较小值。
2.2.7 延时应答
延时应答:
默认情况,接收方收到数据报第一时间返回ACK,但是可以通过延时应答,延时返回ACK的方式提高效率。
返回窗口的大小跟流量控制,接收缓冲区剩余容量的大小有关,当接收到数据报的时候,等一会,程序就会消耗缓冲区的数据报,这样我们返回的ACK的窗口大小(剩余容量)就可以比不等直接返回的大,提高效率。
但是如果程序消耗的速度比不上发送方的发送速度,引入延时机制相反还会是窗口大小变小,降低效率。
延时应答限制:
- 数量限制: 每隔N个包就应答⼀次;
- 时间限制: 超过最⼤延迟时间就应答⼀次;
图解:
2.2.8 捎带应答
捎带应答:
引入了延时应答,接收方得到数据后,不会立刻返回当前数据报的ACK,那么下次返回数据的时候,捎带把上次的ACK带回去。
图解:
2.2.9 面向字节流
面向字节流:
创建⼀个TCP的socket, 同时在内核中创建⼀个 发送缓冲区 和⼀个 接收缓冲区;
• 调⽤write时, 数据会先写⼊发送缓冲区中;
• 如果发送的字节数太⻓, 会被拆分成多个TCP的数据包发出;
• 如果发送的字节数太短, 就会先在缓冲区⾥等待, 等到缓冲区⻓度差不多了, 或者其他合适的时机发
送出去;
• 接收数据的时候, 数据也是从⽹卡驱动程序到达内核的接收缓冲区;
• 然后应⽤程序可以调⽤read从接收缓冲区拿数据;
• 另⼀⽅⾯, TCP的⼀个连接, 既有发送缓冲区, 也有接收缓冲区, 那么对于这⼀个连接, 既可以读数据, 也可以写数据. 这个概念叫做 全双⼯
由于缓冲区的存在, TCP程序的读和写不需要⼀⼀匹配, 例如:
• 写100个字节数据时, 可以调⽤⼀次write写100个字节, 也可以调⽤100次write, 每次写⼀个字节;
• 读100个字节数据时, 也完全不需要考虑写的时候是怎么写的, 既可以⼀次read 100个字节, 也可以⼀
次read⼀个字节, 重复100次;
粘包问题:
- 粘的是“应用层数据包”
- 在TCP的协议头中, 没有如同UDP⼀样的 “报⽂⻓度” 这样的字段, 但是有⼀个序号这样的字段.
- 站在传输层的⻆度, TCP是⼀个⼀个报⽂过来的. 按照序号排好序放在缓冲区中.
- 站在应⽤层的⻆度, 看到的只是⼀串连续的字节数据.
- 那么应⽤程序看到了这么⼀连串的字节数据, 就不知道从哪个部分开始到哪个部分, 是⼀个完整的应⽤层数据包.
解决方法:
- 在TCP角度无解,在应用层解决。
- 法1:约定包与包之间的分隔符(包的结束标志);
- 法2:约定包的长度(例如固定开始几个字节表示接下来的数据包的长度)
2.2.10 异常情况处理
- 进程终⽌:进程终⽌会释放⽂件描述符,仍然可以四次挥手发送FIN。和正常关闭没有什么区别。
- 机器重启/正常关机:本质上还是先杀死所有进程,和进程终⽌的情况相同。
- 接收端掉电:触发超时重传,触发“重置连接”,发送方方主动发送一个复位报文RST,还没回应就断开连接。
- 发送方掉电:发送方一直不发,接收方等到一定时间,像发送方传输一个特殊报文“心跳包”,不携带数据,为了触发ACK,还是没有就断开连接。
- ⽹线断开:就是相当于接收方和发送方同时掉电了。两边都进行操作。
三、TCP、UDP对比
TCP,UDP对⽐:
- TCP是可靠连接,但是TCP不⼀定就优于UDP。TCP和UDP之间的优点和缺点,不能简单、绝对的进⾏⽐较
- TCP⽤于可靠传输的情况,应⽤于⽂件传输,重要状态更新等场景;
- UDP⽤于对⾼速传输和实时性要求较⾼的通信领域,例如,早期的QQ,视频传输等。另外UDP可以⽤于⼴播;