传输层_UDP
大家好,我是bug郭,一名双非科班的在校大学生。对C/JAVA、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流
作者简介:
- CSDN java领域新星创作者blog.csdn.net/bug…
- 掘金LV3用户 juejin.cn/user/bug…
- 阿里云社区专家博主,星级博主,developer.aliyun.com/bug…
- 华为云云享专家 bbs.huaweicloud.com/bug…
传输层
虽然除了应用层其他四次都是由操作系统内核实现,但是传输层协议的学习有助于当我们代码出现bug
更加精准的找bug
定位问题,修改问题!
我们知道传输层协议很多,但是我们主要来学习TCP
和UDP
这两个协议!
端口号
范围: 2个字节大小; 0-65535之间的整数
知名端口号:把0-1024这些端口号划分为一些具体的作用
很多网络服务器是非常常用的
未来方便管理,及将这些服务分配了一些专门的端口号
这里并不是强制要求,而是建议!
例如:
80 http服务器
443 https服务器
22 ssh
23 ftp
…
我们自己部署http端口也可以绑定其他的端口,就像java
中的tomcat
就没有将http绑定在80端口,而是绑定在了8080端口!
UDP
学习一个协议很多时候就是研究他的报文格式
这里的报文格式排版并不之前,只是因为美观所以这样,实际上的报文格式如下所示:
就是我们之前分装的数据格式!
- 源端口
源端口就是保存该主机程序的端口号 - 目的端口
目的端口就是接收方主机程序服务器的端口号 - 报文长度
这里的报文长度范围是2个字节大小,也是就0-65535,单位是字节!
也就是最大的报文长度64k
一次传输的UDP传输层协议报文只能保存64k
数据! - 校验和
校验和就是检验接收方接收到的数据是否正确!
如何校验呢?
数据内容参与校验!
例如:
你要去买饮料,寝室的人都叫你带,而且买的饮料都不一样,这时,你如何知道有没有买正确呢?我们可以根据人数就可以确定数量是否正确,然后更加每瓶饮料的首个字,保存下来,然后对照买的饮料看看是否一样!
通过这样的方法,就可以校验是否正确!
而这里的内容校验也是类似,可以保证绝大多数时间我们接收的数据都是正确的!
TCP面试重点
我们看到TCP
协议报文格式比较复杂!
- 源端口:保存请求方服务程序端口号
- 目的端口:保存响应方服务器端口号
- 32位序号:因为TCP是面向字节流传输,TCP对传输的数据按字节顺序进行编号.
例如:我要传输200个字节的数据,然后数据的确认序号为100,说明我是从字节序号为100的数据开始传输传输200长度字节!- 32位确认序号:就是发送方期待响应方发送已经接收到的字节序号的下一个字节序号(告诉发送方下一次要发送的数据字节开始顺序)
例如:我们发送方从100字节序号发送200个字节数据,接收方接收后,就应该返回301的确认序号给发送方!- 4位数据偏移(首部长度):也就是tcp的报文头大小这里的单位是4字节,也就是15*4字节= 60字节,协议报头可以有60字节大小
6位保留位:用于后期扩展,保留今后使用,但目前应都位0- 6位标志位:
1.紧急URG:当URG位为1时,紧急指针字段有效,表示这个协议报中存在紧急数据需要优先处理
2.确认ACK:当ACK标志位为1时,确认号字段有效,TCP规定在连接建立之后ACK标志位要置为1
3.推送PSH:当两个应用进程进行交互式通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应,这时候就将PSH=1
4.复位RST:当RST=1,表明TCP连接中出现严重差错,必须释放连接,然后再重新建立连接;
5.同步SYN:在连接建立时用来同步序号.当SYN=1,ACK=0时表示发送连接请求报文,当响应方同意建立连接后发送SYN=1,ACK=1给请求方!
6.终止FIN:用来释放连接,当FIN=1时,表示数据以全部发送请求释放连接!
- 16位窗口:通知接收方,我发送的文本,需要留有多大的空间接收
- 16位校验和:检验接收的首部和数据是否出错!
- 16位紧急指针:指出本协议报文紧急数据的字节数
- 选项:可变长度不像udp报头固定了8字节,tcp留有扩展的余地!
- 填充:用于存放完整应用层的数据载荷
我们通过之前对TCP的学习已经对TCP协议特点有所了解!
- 面向字节流
- 全双工
- 可靠传输
- 有连接
上面的这些特点在我们的套接字编程中TCP中都有所体现,除了可靠传输!
那么TCP是如何保证数据传输的可靠性呢?
TCP
原理
TCP
协议需要保证传输数据的安全可靠性,还有数据传输的传输效 率!
所以TCP的设计原则:在保证可靠传输的基础下尽可能提高传输效率!
下面是TCP设计的一些原理策略!
确认应答
我们刚刚学习32位序号和确认序号时,已经知道TCP
由于面向字节流的特点,对传输的数据按照字节顺序进行编号!然后返回确认序号!
如果不对数据进行编号会怎样呢?
当小明发了两条消息给李华时!
这时小明收到"好呀好呀"不知道是啥意思了,因为他发送了两条消息,这是上号还是学习呀,就很迷!
如果我们有确认序号就帮我们解决了这个问题!
小明接收到李华发送的消息,有了确认序号2,表示李华已经接收到了第一条数据,并且给了回应!希望小明发送第二条数据!这就是序号和确认序号的作用!TCP对每个数据都进行了编号!
每次接收方接收到了数据,就会发生一个ACK确认已经之前的数据已经全部接收到,可以继续发送数据了!
确认应答策略保证了数据传输的可靠性!
超时重传
超时重传相当于对确认应答进行了补充!
我们知道我们网络传输的环境十分复杂,有可能会存在数据丢失丢包的情况,我们此时如何保证数据传输的可靠性呢?
网络正常:
当网络正常没有掉包时,刘备通过张飞发送的"好啊好啊"ACK可以知道张飞已经接收到消息,我们的消息发送成功!
但我们没有接收到ACK时!
当我们没有收到接收方传来的ACK时,我们也不知道是我们的数据丢包了,还是对方的ACK丢包了,这时就无法知道接收方,是否已经接收到了数据!
此时发送方等待了会,没有接收到ACK时会将消息再次发送,这就是超时重传!
可能有人就会说了,那如果是ACK丢了的话,如果我们再次发送一条消息,那消息不就重复了呀?
我们的ACK是在操作系统内核发送的,也就是是说,如果接收方接收到了数据,首先到了接收方操作系统socket的接收缓存队列(阻塞队列)中,然后会记录下接收数据的数据编号,然后将ACK
发送个发送方!
如果我们数据丢包了,接收方的接收数缓冲区就没有该数据,会将该数据编号保存,发送一个ACK确认序号!
ACK
丢了,发送方再次发送数据到接收方,先到了操作系统内核,然后呢保存到接收缓冲区,发现已经有该数据了,就直接丢弃,就不会再给接收方这个数据了!
这就保证了应用程序调用socketapi
拿到的数据不重复!
当网络只是发生抖动,那么超时重传就能保证传输继续!
但是当网络遭受重创,直接卡了网线!
那么无论如何重传也无济于事,那这是发送方就不会一直重传下去了!
并且每次重传的时间间隔会越来越大!
最后停止重传!
这里的每次重传的时间间隔并没有准确的值,也可以自行设置!
连接管理(面试重点)
我们知道TCP
是有连接的,所以传输数据之前必须双方进行连接!
那么如何进行连接呢?
3次握手
3次握手就是客户端和服务器建立连接的交互过程
这里的握手只是一个比喻,一次握手就好比一次交互过程,这里进行了3次握手也就是客户端和服务器建立连接需要进行3次交互才能实现!
3次握手就类似于打电话刚接通的过程:
经过这3次交互过程我们就可以知道双方的通话环境是否ok!
第二次握手,可以知道客户端的发送能力和服务器的接收能力没有问题!当进行最后一次交互握手过程时,就可以确认通信双方的可以进行通信!
上图就是客户端和服务器进行3次握手的过程!
TCP的状态:
LISTEN
状态,表示服务器可以进行连接,等待连接状态,就好比手机开机,网络良好,等待电话!
ESTABLISHED
:表示通信双方已连接成功,就好比已经接通了电话,可以进行信息交流了!
3次握手有啥用?和可靠传输有什么关系?
- 3次握手相当于投石问路,检查一下通信双方的网络状态,是否满足可靠传输的基础,如果网络状态不好,就没有进行数据传输的必要了!经历了3次握手就可以验证双方的发送能力和接收能力,就好比打电话双方打通后需要验证双方的麦克风和喇叭!
- 让双方能够协商一些重要信息
为啥是3次握手,不能是4次?或者2次嘛?
上图就是4次握手,可以4次但是没有必要,我们可以将第二次ACK
和第3次SYN
放在一个数据包中传输,没必要分开进行分封装分用,就好比你去一家店铺买2件衣服,商家肯定打包成一个包裹!
这里分开传输效率低!不如和在一起!
2次握手显然不行,因为进行次握手后,客户端知道了自己的发送能力和接收能力良好,但是服务器不清楚自己的发送能力和接收能力是否良好,进行3次握手双方才能确认了双方通信状态,进行接下来的数据传输!
3次握手就好比2个人谈恋爱是一歌双向奔赴的过程,所以其中的交互缺一不可,不然就不能确立男女朋友关系!
4次挥手
4次挥手客户端和服务器断开连接的过程!我们在进行3次连接后,在操作系统内核中保存了一些连接的信息,就是我们之前学过的五元组!断开连接的过程就是将保存的信息删除!
也就是相当于情侣之间分手的过程!
当俩个人确认关系后,那么双方会在心里留一块位置给对方,起码知道对象叫啥名,不然谈啥恋爱对吧,然后4次挥手就把心里的位置给腾开,把之前双方的信息给销毁!
CLOSE_WAIT
:四次挥手进行了2次后的状态,这个状态就是等待代码中调用socket
api中的close
方法进行接下来的挥手,如果一个服务器中出现了大量的该状态,大概率出现了bug!
TIME_WAIT
:谁发起的FIN
谁就进入了该状态,表面上看A
发送了ACK
就没撒事了,但是有可能出现最后一个ACK
丢包问题,所以TIME_WAIT
状态会等待B
的超时重传!要保证,B重传时,A还在连接!
一般A的等待时间是2*MSL
,MSL是网络间,任意两点传输的最长时间!
我们此时又在想:3次挥手中间的ACK
和SYN
合在了一起,提高了传输效率,那么这里为啥不能是3次挥手呢?
3次握手中间两次可以合并,都是由操作系统内核完成!
而4次挥手有时候不能合并!
不能合并的原因B发送ACK
和FIN
的时机不同,ACK
是由操作系统内核发送,而FIN
是代码中的socket.close
方法才会触发,有时两者的时间间隔太大无法合并一起!
- 点赞
- 收藏
- 关注作者
评论(0)