深入理解TCP/IP传输层

时间:2022-08-28 16:02:39

传输层:负责数据能够从发送端传到接收端(只需要关注点对点的传输,中间的传输过程一概不管)

UDP和TCP

UDP(全双工):
1.无连接,2不可靠,3.面向数据报

深入理解TCP/IP传输层

分别表示UDP源端口号、目的端口号、UDP长度、UDP检验和

端口号在传输层的概念:区分这个数据要交给哪个程序去处理,启动一个服务器,会和一个端口号相绑定,一般HTTP绑定在80端口号,来区分发件人和收件人

UDP的报文长度最多是64k,这是一个比较小的数字,这就限制了应用层协议的数据长度,一旦数据长度超出了UDP的表示范围,就会出现问题

可以在应用层通过代码,将数据拆分成多个数据报,再使用多个UDP数据报来分别发送

代码实现的成本大大提高了

校验和(检验和):比较简短,同时最好能和内容相关联

UDP中使用的是CRC循环冗余校验的方式

uint16_tchecksum1 =0;
for(依次遍历数据包的每个字节){
checksum+=当前字节的值
}

发送者在发送前先计算了一个校验和checksum1

就把数据和checksum1一起发送到对端

接收端也按照相同的规则计算校验和checksum2

对比checksum1和checksum2是否相同

校验和出错就会直接丢弃


UDP的特点:

无连接:知道对端的IP的端口号就可以直接传输,不需要建立连接

不可靠:没有确认机制,没有重传机制,如果因为网络故障该段无法发送到对端,UDP协议也不会给应用层返回任何错误信息

面向数据报:不能灵活的控制读写数据的次数和数量

面向数据报
 应用层交给UDP多长的报文,UDP原样发送,既不会拆分,也不会合并

用UDP传输100个字节的数据:

如果发送端调用一次sendto, 发送100个字节, 那么接收端也必须调用对应的一次recvfrom, 接收100个字

节; 而不能循环调用10次recvfrom, 每次接收10个字节

基于UDP的应用层协议 
当然, 也包括你自己写UDP程序时自定义的应用层协议

NFS: 网络文件系统
TFTP: 简单文件传输协议
DHCP: 动态主机配置协议
BOOTP: 启动协议(用于无盘设备启动)
DNS: 域名解析协议


TCP协议

深入理解TCP/IP传输层

TCP(全双工,是一个比较复杂的协议 )协议特点:

1.有连接:需要用端口号建立连接

2.可靠传输:发送者能感知到是否发送成功

3.面向字节流:字节流读取数据

TCP最核心的机制 :

1.可靠传输

2.尽可能提高传输效率

可靠性传输 发送者能感知到失败(对比打电话和发短信)
面向字节流,文件操作(I/O流)

全双工:既能发送也能接受

UDP虽不可靠,但传输效率比TCP高

TCP通过判断发送的消息是否被回复,来判断是否可靠传输
一、确认应答(可靠性的核心机制)
序号来说,按照每个字节的方式来编号的.
确认序列来说,表示当前序号之前的数据已经正确收到了

接下来对端应该给我发送确认序号开始的数据


二、超时重传(可靠性的核心机制)和确认应答相辅相成

如果对方没有确认应答,此时隔一定的时间之后,就需要重复传输这样的数据,

重传是为了进一步降低丢包的可能性,重传的间隔时间采用的是一种比较悲观的态度,

等待的时间越来越长

如果达到一定次数之后对方还没有响应,就断开和对方的通信连接

如果是应答数据包丢失(ACK),同样会超时重传,此时就导致接收方收到了两份相同的数据,TCP会跟据序号来自动去重


三、连接管理(也是可靠性的一部分)

建立连接的意义:

1.双方先试探下对方是否适合和我通信

2.双方可以协商一些重要数据,序号从几开始

三次握手

深入理解TCP/IP传输层

深入理解TCP/IP传输层

深入理解TCP/IP传输层

三次握手中涉及到的状态变化

1.LISTEN状态(服务器):手机开机,并且信号良好

2.ESTABLISHED状态(客户端/服务器):电话拨通之后对方接听了

第一次握手:建立连接时,客户端发送syn包(syn=1)到服务器,客户端进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手

为什么要三次握手?

  三次握手的目的是建立可靠的通信信道,说到通讯,简单来说就是数据的发送与接收,而三次握手最主要的目的就是双方确认自己与对方的发送与接收机能正常

四次挥手的过程:

深入理解TCP/IP传输层

深入理解TCP/IP传输层

双各自向对方发送FIN,再各自向对方发送ACK 

中间的两次交互可能合并为一个(在特殊情况下仅仅是可能,所以有些情况下是三次挥手)

第一次挥手,client:我说完了
第二次挥手,server:我知道了(但此时server可能还有话要说)
第三次挥手,server:我也说完了
第四次挥手,client:我知道了,(双方挂了电话)
为什么要四次挥手?
答:根本原因是,一方发送FIN只表示自己发完了所有要发的数据,但还允许对方继续把没发完的数据发过来。

举个例子:

A和B打电话,通话即将结束后,A说“我没啥要说的了”,B回答“我知道了”,但是B可能还会有要说的话,A不能要求B跟着自己的节奏结束通话,于是B可能又巴拉巴拉说了一通,最后B说“我说完了”,A回答“知道了”,这样通话才算结束。

双方各自向对方发送FIN,再各自向对方发送ACK

中间的两次交互,可能合并成一个(四次挥手变为三次挥手)

四次挥手的状态转换:

1.CLOSE_WAIT:收到第一个FIN的一方进入CLOSE_WAIT,是为了等待代码中调用 关闭 方法

如果你发现服务器上出现大量的CLOSE_WAIT状态,意味着什么?意味着代码有bug,忘记调用close方法了

2.TIME_WAIT:主动断开链接的一方进入到TIME_WAIT状态,存在的意义是一旦最后一个 ACK 丢包,还有机会进行重传

TIME_WAIT 会存在一定的时间,在超出这个时间之后,TIME_WAIT状态才会真正消失,释放对应的链接

2MSL:

MSL表示互联网上任何两点之间传输数据的最大时间    1min


四、滑动窗口(提高传输效率)

窗口的意义是:不等待ACK的情况下最多发送多少数据

滑动的含义是:每次收到 ACK 数据的同时,就继续往后发下一组数据

如果窗口越大,传输效率越高

窗口也不能无限大,如果窗口太大可能会影响到可靠性

滑动窗口中如果丢包,采用快速重传的方式来进行重传

快速重传:快速重传本质上就是超时重传,只不过重传的时候,没有拖泥带水,只重传了真正丢包的数据


五、流量控制

窗口越大,传输效率越高,但是窗口也不能无限大

如果窗口太大,可能接收端,处理不过来

若果生产速度超过了消费速度,接受缓冲区的内容就会越积越多,达到一定程度,缓冲区满了,此时再传输的数据就会丢包

使用 接受缓冲区空余空间的大小,用这个指标衡量接收端的处理能力

通过这个指标来控制发送端的窗口大小(发送速度)

接收端缓冲区空余空间的大小,作为TCP协议报头中的窗口大小,这个值就是发送端的滑动窗口大小的一个“建议值”


六、拥塞控制

深入理解TCP/IP传输层

滑动窗口的窗口大小不能无限大,即使接收端处理速度很快,也可能因为网路环境不佳导致数据丢包

最终的 滑动窗口大小是由 流量控制 和 拥塞控制 共同决定的

拥塞窗口:拥塞控制机制所建议的窗口大小,从一个比较小的数字开始,如果网络通畅,放大窗口大小,如果网络丢包,

缩小窗口大小

滑动窗口的最终值就是:流量控制的窗口 和 拥塞窗口 的较小值

慢开始:刚开始传输的时候拥塞窗口设置的小一些


七、延时应答(提高传输效率)

在可靠性的基础上,尽量提高窗口大小

也是和滑动窗口以及流量控制相关

流量控制中需要在ACK中反馈接受缓冲区剩余空间的大小

此时采取的策略是,收到数据不立刻返回ACK,而是等一会,

等的过程中,程序就能多消费一些缓冲区中的数据,从而导致反馈的窗口大小就要更大一些


八、捎带应答(提高传输效率)

建立在延时应答的基础上的

内核反馈ACK的实际和程序反馈响应的时机合二为一,通过同一个数据报同时带上两方面的信息


九、面向字节流

粘包问题

由于面向字节流读取数据方式没有具体的约定,很难从接受缓存区中直接获取到一个完整的应用层数据报

解决粘包问题只能从应用层角度入手,只要在应用层协议设定的时候,明确包的边界就可以了

1、指定分割符

2、指定包的长度


十、异常情况

1.程序异常结束(没啥影响,四次挥手正常完成)

2.系统关机(没啥影响,本质上就是要先强制关闭所有程序)

3.主机掉电(拔网线)

a.掉电的是接收方,发送方会触发超时重传,尝试重新建立链接,彻底释放链接

b.掉电的是发送方,接收方如果一直接收不到数据的话,达到一定的时间,就会给对方

发送一个“心跳包”,如果没有心跳了,就会重新尝试链接,如果链接建立失败了,彻底释放链接


TCP和UDP的对比:

1.如果需要使用可靠传输,优先考虑TCP

2.如果传输的单个数据报比较大,还是考虑TCP

3.如果对可靠性要求没那么高,但是对性能要求很高,优先考虑UDP

4.如果需要实现广播,优先考虑UDP


如何使用UDP来进行可靠传输?

只能在应用层,通过代码来手动实现