IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 传输层协议之UDPTCP -> 正文阅读

[网络协议]传输层协议之UDPTCP

网络协议分层之传输层

负责端对端的数据传输,只考虑起点和终点,不考虑中间过程。
传输层是操作系统内核实现的,因此谈到的传输层协议,一般都是指线程的一些协议,很少会涉及“自定制”。

UDP的特性


1.无连接
2.不可靠
3.面向数据报
4.全双工

无连接:socket创建好之后,就可以立即尝试读写数据了
有连接:socket创建好了之后,还需要建立连接,连接建立完了,再通过accept获取到连接,才能进行读写数据。

可靠/不可靠:

面向数据报:读写数据都是以DatagramPacket为单位进行的
面向字节流:读写数据直接以byte[]为单位

全双工:一个socket,既能读(socket.receive),也能写(socket.send)

几个概念:
1.端口号
端口号的用途:标识一个进程,就可以区分出当前收到的数据要交给哪个进程来处理。

端口号是一个整数,是一个两个字节的整数,0-65535(没有负数)
0-1023 这些端口,称为“知名端口号”。

通常情况下,两个进程无法绑定到同一个端口号。
一个进程可以绑定多个端口,绑定,不是把进程和端口绑定,而是把socket(socket就是文件,一个进程里可以有很多文件,也就可以有很多socket,每个socket都可以绑定到不同的端口)和端口绑定。

进程是通过同一个网卡来传输数据的,让每个进程分别绑定不同的端口号,数据包中有一个“目的端口”字段,会根据目的端口找到对应的端口号的进程,然后把数据交给对应的进程。

PID:每次进程启动之后,都在发生改变(系统自动分配)
在这里插入图片描述

UDP协议报文格式:
【UDP报头 | UDP数据(完整的应用层数据报)/UDP载荷(payload)】【源端口号|目的端口号|UDP长度|UDP校验和】【】

关于UDP长度:
整个UDP数据报的长度,使用2个字节的数据来表示,2个字节能表示的数据范围是0-65535byte,也就是一个UDP数据报,最大就是64KB。如果报文长度超过64KB,此时就可能丢失一部门数据,解决办法是改用TCP,TCP对于数据的长度没有限制。

实际使用的校验的算法有很多,其中比较常见的有crc(循环冗余校验)和md5校验。

crc(循环冗余校验)
假设有一串数据,把它当成二进制的数据,依次按照字节为单位,取出数据,然后把这些数据进行累加。发送以前算一遍crc,接收到之后也算一遍crc,如果这个数据发送前和发送后,数据内容不变,得到的crc也是一致的。
如果传输过程中出现了比翻转,接受到的内容和发送的内容就不一样了,此时算出来的两份crc也就是大概率不相同的。

md5算法校验(本质是“非对称的哈希算法”)

TCP的特性:


1.有连接
2.可靠传输(确认应答)
3.面向字节流
4.全双工

TCP协议的报文格式
在这里插入图片描述
【TCP报头/首部(header) | TCP数据/载荷(payload)】
首部前面一共是20个字节,options部分,范围就是0-40个字节,所以首部最长是60个字节。
在这里插入图片描述
这六个比特位,标识了这个TCP数据报是一个什么类型的数据报。

保证可靠性的核心是确认应答【可靠性】

发送方法数据给接收方,接收方就回应一个应答报文。如果发送方收到了这个应答报文,那么认为是对方已经收到了。如果发送方发送了多条数据,接受方也回复了多条数据,但是网络上存在一种常见的情况:后发先至。因此不能就单纯的通过收到数据的顺序来确定逻辑,就需要对应答进行编号(报文中的序号与确认序号)。

TCP传输数据是按照字节来算的(面向字节流),TCP的序号和确认序号,是以字节为单位进行编号的。
在这里插入图片描述
在这里插入图片描述

超时重传【可靠性】
数据在传输的过程中如果发生丢包,就要进入超时重传的机制中,每次重传的等待时间会逐渐增加。

如果网络大体是正常的,那么出现连续两次甚至连续三次都丢包的概率,是非常低的。

如果重传导致数据重复了怎么办?
接收方收到的数据会先放在内核的“接受缓冲区中”(一段内存,每个socket都有),按照序号来进行去重,此时在应用程序中读取数据,读到的结果就是不带重复的。

连接管理【可靠性】

TCP是有连接的,连接管理就是如何建立连接(三次握手),如何断开连接(四次挥手)
在这里插入图片描述
本质上,就是A向B请求连接,B给予回应,B也向A请求连接,A给予回应。
本来应该是“四次握手”,但是中间两次操作,是可以合在一起的。这两个操作在时间上是同时发生的。

正常情况下,SYN这一位是0,在尝试请求连接的请求中,这一位是1。
正常情况下,ACK这一位是0,在进行确认应答的时候,这一位是1。

为什么要三次握手,为什么要建立连接?

  1. 通过三次握手的过程,来确认A和B之间的传输是通畅的,尤其是要确认,A和B各自的发送能力和接收能力是否正常。
  2. 协商参数,通过三次握手,让A和B之间通通气,选择一些传输中合适的参数,例如,TCP的序号从几开始。
    在这里插入图片描述
    四次握手也可以,但没有必要。两次握手不行。

三次握手过程中涉及到的一些状态转换

  1. LISTEN:手机开机,信号良好,随时可以打入电话
    当我们创建好ServerSocket实例的时候,就进入了LISTEN状态

2.ESTABLISHED:接通了电话,双方可以说话了
代码中accept返回了,得到了一个clientSocket

四次挥手
在这里插入图片描述
结束报文段:FIN

ACK和FIN为什么不合并?
对于B来说,ACK和FIN的触发实际是不一样的
B只要收到FIN就会立即触发ACK,这个事是内核完成的
B发送FIN的实际是用户代码控制的(代码中出现了socket.close()这样的操作的时候,才会触发FIN)
在这里插入图片描述
四次挥手中的状态变化
CLOSE_WAIT:服务器收到FIN之后进入的状态,等待用户代码调用close,来发送FIN~
TIME_WAIT:表示的客户端收到了FIN之后进入了TIME_WAIT
这个状态存在的意义主要就是处理最后一个ACK丢包

出现丢包的话,客户端就会重传FIN

如果服务器上出现大量的CLOSE_WAIT,是代码出现bug,close没有及时被调用到。

四次挥手是否可能变成三次挥手?
有可能,虽然ACK和FIN不是同时的,但是在延时应答和捎带应答的情况下使有可能合并在一起的。

滑动窗口【效率】
在这里插入图片描述
在这个过程中,发送方要花很多时间来等,这个等待其实就浪费了大量的时间。
在这里插入图片描述
一次批量发的数据的长度,称为“窗口大小”,如果窗口越大,整体的效率就越高。但是也不能无限大,完全不等ack。

针对多个ack在网络上传输的情况,如果后面的ack先到,表示之前的数据也被对方收到了,那么之前的ack收到或没有收到已经不重要了。

如果在滑动窗口的场景中出现丢包了,怎么办?
没有关系,只要不是全丢就好了,因为有快速重传机制,如果发生丢包,接受方就会多次索要丢失的数据,收到三个同样的确认应答是则进行重发,后续已达到的数据保存在缓冲区中。当丢失的数据重传之后,后续的数据

流量控制【可靠性】

对滑动窗口的进一步补充,窗口太大太小都不合适,此处流量控制室基于接收方的处理能力来限制窗口大小(接收缓冲区的剩余空间)的。

返回的ACK会把缓冲区的剩余空间发送给对方。

如果窗口为0,发送方不再发送数据,但是为了能够查询当前接收方的窗口大小,每隔一段时间,还会再来触发一个窗口探测包,通过这个包(不传输具体的业务数据)触发ack,在这个ack中就能够知道当前窗口的大小了。

拥塞控制【效率】

站在另外一个角度来限制发送方的窗口大小。
在这里插入图片描述
站在一个宏观的角度来看待这个问题,把整个中间的链路都看成了一个整体,只看结果。

先使用一个较小的窗口来传输数据,看看是否丢包,如果不丢包,说明网络比较通畅,如果丢包,说明网络发生拥堵。

当网络通畅的时候,就逐渐加大发送速率,当网络出现丢包的问题,就立即降低发送速率。如果达到阈值,就从指数增长变成线性增长。

通过这样的方式,就可以逐渐实验出一个比较合适的窗口大小。
真实的发送窗口的大小=min(流量控制的窗口,拥塞控制的窗口)

延时应答【效率】

在延时应答的这段时间,应用程序就会消费一部分数据,此时缓冲区的剩余空间就更大了。

捎带应答
正常情况下,服务器内核收到数据,就会立即返回ack,但是由于有了延时应答,返回的ACK不是立即返回,而是等一会,正好在这段时间,服务器要返回业务上的response了,此时就可以把这个ACK和response合二为一,把两个包变成一个包。

面向字节流【其他】

在这种面向字节流的情况下,需要注意一个重要的问题:粘包问题

应用程序从接收缓冲区读数据的时候,不知道从哪到哪是一个完整的应用层数据报。

解决办法(核心就是明确应用层数据中,包和包之间的边界)

  1. 给应用层数据设定“结束符”/“分隔符”
    约定,每个应用层数据报一定以;结尾
  2. 给应用层数据设定“长度”
    设定包的长度,约定每个应用层数据报的前4个字节,存储数据报的长度

异常情况【其他】
常见的异常情况:
1.进程终止
不管进程是怎么终止的,本质上都会释放对应的PCB,也会释放对应的文件描述符,一样会触发四次挥手。
“进程终止”不代表连接就终止,进程终止其实就相当于调用了socket.close()而已

2.机器重启
机器重启的时候,其实也是先杀进程,仍然是进行四次挥手

3.机器掉电/网线断开
①掉电的是接收方
此时另外一边还在发送数据,此时显然发送发不会再有ACK
于是就会超时重传,重传几次之后,就会尝试重置连接,用到复位报文段(RST),再然后发送方就会放弃这个连接,把连接对应的资源就回收了。

②掉电的是发送方
此时另外一方在尝试接受数据,此时接受不到任何数据
接受方如何知道,发送方式挂了,还是说发送方暂时还没发呢?
此时接收方采取的策略,就是“心跳包”机制(也叫做“保活”)
每隔一段时间,向对方发送一个PING包,期待对方返回一个PONG包
如果PING包发过去,过了很久还没有PONG,并且重试几次也不行,此时就认为对方已经挂了。

如何基于UDP协议实现可靠传输?

看似在问UDP,其实在问TCP
1.实现确认应答机制,把每个数据接受到之后,都要反馈一个ACK(不是内核返回,而是应用程序自己定义一个ack包,发送回去)
2.实现序号/确认序号,以及实现去重
3.实现超时重传
4.实现连接管理
5.要想提高效率,实现滑动窗口
6.为了限制滑动窗口,实现流量控制/拥塞控制
7.实现延时应答,捎带应答,心跳机制

什么样的场景中适合使用TCP,什么样的场景适合使用UDP?
1.如果需要可靠性,选TCP
2.如果传输的单个数据报比较长(超过64K),使用TCP
3.如果特别注重效率,优先考虑UDP
4.如果需要广播,优先考虑UDP
一份数据同时发给多个主机,UDP自身就支持广播,但是TCP自身是不支持的,就只能在应用层中通过多个连接,轮询的方式给每个主机发送数据(伪广播)

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-11-15 16:11:28  更:2021-11-15 16:11:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 7:23:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码