传输层————TCP/UDP

目录

一、传输层

1、再谈端口号

2、端口号范围

3、UDP协议

什么是协议

端口号为什么是16位

为什么说UDP是面向数据报的

4、文件系统和socket的关系

5、TCP协议

系统中的存在形式

如何分离报头和有效载荷

如何分用

如何确保TCP的可靠性(解决丢包)

TCP常规的通信模式

TCP通信的一般模式

确认序号

互相发的是什么

为什么要有两个序号

16位窗口大小

标志位

什么是标志位

为什么有标志位

理解TCP缓冲区

6、TCP超时重传机制

如何看待丢包问题

超时重传

超时时间

7、TCP链接的管理机制

三次握手

TCP三次握手,为什么是三次

四次挥手

为什么是四次挥手

可以三次挥手吗

CLOSE_WAIT

TIME_WAIT

TIME_WAIT的作用

如何保证陈旧报文对新连接产生干扰

8、滑动窗口

什么是滑动窗口

滑动窗口在哪里

如何滑动

滑动窗口的大小

9、报文丢失

10、应答丢失

11、流量控制

接收端如何把窗口大小告诉发送端

12、拥塞控制

13、延迟应答

14、捎带应答

15、如何解决粘包问题

16、TCP异常情况


一、传输层

1、再谈端口号

在TCP/IP协议中,用源IP,源端口号,目的IP, 目的端口号,协议号这样一个五元组来标识一个通信(可以通过netstat-n 查看)

2、端口号范围

0-1023:知名端口号,HTTP, FTP,SSH等这些为使用的应用层协议,他们的端口号都是固定的

1024-65535:操作系统动态分配的端口号,客户端程序端口号,就是操作系统从这个范围分配的

3、UDP协议

什么是协议

客户端和服务端约定的结构化字段

端口号为什么是16位

内核认为端口号为16位 报头和有效载荷分离如何做到 报头长度是固定的

为什么说UDP是面向数据报的

(1)对报文的重新理解

OS内部一定存在大量的的报文,不同层也一定存在多个报文,我们需要先描述,在组织

(2)系统中的报文

(3)封装

data -= (sizeof(tcphdr/其他报头))

(struct udphdr *) data -> XX = YY

(4)解封

(mac*) (sk_buff->data) -> XXX;

sk_buffer-> data+= sizeof(IP)

4、文件系统和socket的关系

5、TCP协议

系统中的存在形式
如何分离报头和有效载荷

报头固定长度位20

如何分用

有目的端口号

4位首部长度

表示报头+选项的总长度,单位是:4字节(范围20到60,选项最多40)

如何确保TCP的可靠性(解决丢包)

确认应答性质

TCP常规的通信模式

无论那个朝向的人给我发送一个消息,我都给他发送一个应答,互相保证两个朝向的可靠性,

这种方式十分的低下,在上一个信息得到应答之前我们不可以做任何的事

TCP通信的一般模式

我们发送一堆的信息,在返回一堆的应答,但是发送顺序和接受的顺序并不是一致的,收到的消息可能是乱序的,所以为了保证可靠性,我们报文中有一个序号,将发送的信息进行编号,保证不是乱序的,但是应答我们无法确定是谁的,所以我们需要报文中的确认序号

确认序号

ask_seq表明:该数字之前的报文我已经全部收到,下此发送,请从ack_seq发送

不是对一个报文确认,是对历史所有报文的确认

互相发的是什么

TCP报文

为什么要有两个序号

互相发送的报文可能存在捎带应答(即发送信息又是对历史消息的应答)

16位窗口大小

在我们发送的时候,有时候会有大量的数据,导致对端主机来不及接受,所以我们需要让发送方,知道对端的接受能力(16位窗口表示自己的缓冲区剩余空间的大小)

细节一:流量控制是双向的(如果单行发送,就只做单向流量控制)

细节二:窗口填写的是自己接受剩余空间的大小

标志位
什么是标志位

结构体位端中的比特位,0(无效)1(有效)

为什么有标志位

区分报文的类型

ACK

置1表示该报文是一个确认报文

SYN

置1表示请求建立链接,我们把携带SYN标识的称为同步报文段

FIN

通知对方,本端要关闭l,我们称携带FIN标识的为结束报文段

PSH

提示接收端应用程序立刻从TCP缓冲区把数据带走

细节一:PSH标志位,即便对方还有空间也可以被设置

细节二:应用程序,怎么取数据,应该是应用层自己决定的,所以PSH的功能类似于唤醒进程

RST

用来处理异常的时候,让对方进行链接重置

例如:TCP建立链接是三次握手,不一定100%建立链接成功,如果发送端认为链接已经建立成功但是链接实际没有建立成功,发送端发送消息,对端会发送RST,让链接重置

URG

TCP保证了协议的按序到达,如果有紧急数据,依旧需要排队,所以URG置1表示:内部存在紧急数据由16位紧急指针来指向,当前报文有效载荷部分的一个偏移量,紧急数据一共有1个字节

一种可靠性和效率提高的策略

理解TCP缓冲区

在逻辑上我们可以吧TCP的接受缓冲区,想象成线性结构

这样确认序号和序号就可以自动转化为数组下标

但是物理上不是一个线性结构他是不连续的,实际的缓冲区如下:

6、TCP超时重传机制

如何看待丢包问题
  • 我发的报文,你有没有收到 我知道吗? 知道,如果收到应答则对方一定收到了
  • 我发的报文,丢失了,我知道吗?不知道,没有收到报文有两个情况:我发的报文丢失了,对方的确认应答丢失了
超时重传

如果我们很长时间都没有接受到应答,我们不可能一直等待下去,所以我们需要约定一个时间,确认应答如果超时了,我们判定超时(不叫判定丢包)重发

超时时间

因为网络的畅通程度时浮动的 ,超时时间一定也必须是浮动的,如果太长会导致发送效率降低,而太短会导致误判,重传机制可能被高频触发

在 Linux、BSD Unix 及 Windows 系统中,TCP 超时重传机制以 500ms 为固定基础单位,超时时间始终是该单位的整数倍,具体规则如下:​

  1. 首次重传后若未收到应答,等待 2×500ms 进行第二次重传;
  2. 若第二次重传仍无应答,超时时间按指数级递增,下一次等待 4×500ms 再重传,后续以此类推(即每次超时时间翻倍);
  3. 当重传次数累计达到阈值时,TCP 会判定网络链路或对端主机出现异常,进而强制关闭当前连接。

7、TCP链接的管理机制

三次握手

TCP进行链接的时候需要进行三次握手,代码中由connect发起双方OS自主完成

注意:accept并不参加三次握手

互相发送的是TCP报文

TCP三次握手,为什么是三次

1、验证全双工

验证双方都可以收发消息,网络是通畅的

2、建立双方要通信的共识

三次握手的本质其实是四次握手,因为捎带应答,变成了三次,一发一答确立的双方要通信的共识

互发消息

write本质是拷贝,将信息拷贝到发送缓冲区中。

四次挥手

TCP关闭链接需要进行四次挥手

为什么是四次挥手

双方建立要结束链接的共识

可以三次挥手吗

FIN表达的意思是我要发的数据已经发完了,我要关闭一个通道了(逻辑上),可能客户端关闭链接,但是服务端还有信息发送给客户端

CLOSE_WAIT

一端主动断开链接,另一端未断开链接,另一端会进入ClOSE_WAIT状态,存在fd泄漏问题

TIME_WAIT

主动断开链接的一方,4次挥手已经完成,自己不能立即退出,而是要在等待一段时间(2MSL报文生存的最大生存时间),让自己处于TIME_WAIT状态

TIME_WAIT的作用

理由一:防止陈旧报文对新连接产生干扰,让陈旧报文从网络中消散, 强制要求更换端口号

(但是服务端不可以随意的更改端口号,所以需要设置服务端即使在time_wait状态也可以立即重启)

理由二:保证四次挥手的正确结束

如何保证陈旧报文对新连接产生干扰

1、建立链接握手的时候,交换随机报文起始序号

8、滑动窗口

什么是滑动窗口

指的是暂时无需等待确认应答而可以继续发送数据的最大值

滑动窗口在哪里

发送方的发送缓冲区中

如何滑动

滑动窗口的存在,把发送缓冲区分成了三个部分

左边:已发送,已确认的数据

中间:直接发,暂时不用应答

右边:待发送和空位置

滑动窗口滑动的方向:从左到右

滑动窗口的本质:下标增多,就是滑动

滑动窗口的大小

start = 确认序号

end = start + win

滑动窗口只能向右滑动吗, 能不能向左

不能,因为未发送的数据在右边

滑动窗口的范围大小会变吗

变小:给对方发送数据,但是对方不取数据,接收缓冲区变小,滑动窗口变小

变大:给对方发送数据,对方将所有未取的数据一次性取走了,接收缓冲区变大了,滑动窗口变大

不变:给对方发送数据,对方取等量的数据走,接收不变,滑动窗口不变

9、报文丢失

确认应答表示该数字之前的报文我已经全部收到了

如下如果一个报文丢失了,那么他会应答都是历史已经收到的报文,收到三个同样的确认应答时会启动快重传,快重传提高速率上限,超时重传用来兜底

如果左侧报文丢失(1001~2000)

那么后面所有的确认应答都是1001,导致滑动窗口左侧不会移动(数据传输过程,丢报了,该数据不能从滑动窗口中删除)

如果中间报文丢失(3001~4000)

那么后面所有的确认应答都是2001,滑动窗口的左侧会移动到3001不动,将中间报文丢失传化成左侧报文丢失

如果最右侧报文丢失(4001~5000)

同理会变成左侧报文丢失

10、应答丢失

这种情况下,部分ACK丢了不要紧,可以通过后续的ACK进行确认

11、流量控制

接收端处理数据的速度是有限的。如果发送端发的太快,导致接收端的缓冲区被打满,这个时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应。

因此TCP支持根据接收端的处理能力,来决定发送端的发送速度。这个机制就叫做流量控制。

接收端会把自身可接收的缓冲区剩余空间大小,填入 TCP 首部的 "窗口大小" 字段,通过 ACK 报文告知发送端;

  • 窗口大小字段的数值越大,意味着网络的吞吐量越高;
  • 一旦接收端察觉到自己的缓冲区即将填满,就会把窗口大小设置为更小的值并通知发送端;
  • 发送端收到这个窗口信息后,就会降低自身的发送速度;
  • 要是接收端的缓冲区已经满了,就会将窗口值设为 0;此时发送端不再发送数据,但需要定期发送一个窗口探测数据段,让接收端把当前的窗口大小告知自己。
接收端如何把窗口大小告诉发送端

TCP报文中有一个16位窗口字段

缓冲区大小是否只有65535

不是,TCP报文中选项字段有包含一个窗口扩大因子M,表示窗口字段的值左移M位

刚开始是如何知道对方的窗口大小

三次握手报文交换彼此窗口大小

12、拥塞控制

TCP的滑动窗口机制堪称高效可靠传输大量数据的"大杀器",但即便如此,若在连接刚建立的初始阶段就盲目发送海量数据,依然可能引发网络问题。

究其原因,网络中存在着众多计算机设备,当前的网络状态本身就可能处于拥堵状态。而在尚未摸清网络实时状况的情况下,贸然发送大量数据,无疑会让原本就拥堵的网络"雪上加霜",进一步加剧传输困境。

因此,TCP专门引入了"慢启动"机制:在连接初期,先发送少量数据作为"探路包",通过这些数据的传输反馈来摸清当前的网络拥堵情况,之后再根据探测到的网络状态,动态决定后续的数据传输速率,从而实现更平稳、高效的传输。

此处引入一个概念称为拥塞窗口

  • 发送开始的时候,定义拥塞窗口大小为1;拥塞窗口是一个int,用来衡量网络的拥塞程度的
  • 每次发送数据包的时候,将拥塞窗口和接收端主机反馈的窗口大小做比较,取较小的值作为实际发送的窗口;end = start + min (win ,拥塞窗口)
  • 慢启动最开始是指数正常的,指数函数前期慢(进行探测)增长快(探测后确定不怎么拥堵后尽快恢复正常通信)
  • 为了不让它一直快速增长,引入慢启动的阈值,当拥塞窗口超过这个阈值按照线性方式增长
  • 当TCP开始启动的时候,慢启动阈值等于窗口最大值(最大值= 带宽*RTT)
  • 在每次超时重发的时候,慢启动阈值会变成原来的一半,同时拥塞窗口置回为1
  • 少量丢包,我们仅仅是触发超时重传,大量丢包,我们认为网络拥塞(一般1%~1.5%正常)

13、延迟应答

接收方在接收到信息的时候,不立即应答,而是等一等,概率上接收端的上层回取走一些,应答的时候可以更新一个更大的滑动窗口提升效率

等一等的策略:

  • 小于最大报文生存时间
  • 数量限制:每隔N个包就应答一次(N一般为2)
  • 时间限制:超过最大延迟时间就应答一次(时间一般取200ms)

14、捎带应答

在应答的同时可以携带传递给对端的信息

面对字节流

创建一个TCP的socket, 同时在内核中创建一个 发送缓冲区 和一个 接收缓冲区:

  • 调用write时, 数据会先写入发送缓冲区中;
  • 如果发送的字节数太长, 会被拆分成多个TCP的数据包发出;
  • 如果发送的字节数太短, 就会先在缓冲区里等待, 等到缓冲区长度差不多了, 或者其他合适的时机发送出去;
  • 接收数据的时候, 数据也是从网卡驱动程序到达内核的接收缓冲区;
  • 然后应用程序可以调用read从接收缓冲区拿数据;
  • 另一方面, TCP的一个连接, 既有发送缓冲区, 也有接收缓冲区, 那么对于这一个连接, 既可以读数据, 也可以写数据. 这个概念叫做 全双工
  • 由于缓冲区的存在, TCP程序的读和写不需要一一匹配,
  • 写100个字节数据时, 可以调用一次write写100个字节, 也可以调用100次write, 每次写一个字节; • 读100个字节数据时, 也完全不需要考虑写的时候是怎么写的, 既可以一次read 100个字节, 也可以一次read一个字节, 重复100次;

15、如何解决粘包问题

  • 固定包的大小
  • 包的头部加上包的总长度
  • 包和包之间使用分隔符

16、TCP异常情况

进程终止:进程终止会释放文件描述符,仍然可以发送FIN。和正常关闭没有什么区别。

机器重启:和进程终止的情况相同。

机器掉电/网线断开:发送端网线掉了,回触发硬件中断自动断开链接,接收端认为连接还在,一旦接收端有写入操作,接收端发现连接已经不在了,就会进行reset。发现对方释放sockfd,系统回自动发送信号,杀死进程。即使没有写入操作,TCP自己也内置了一个保活定时器,会定期询问对方是否还在。如果对方不在,也会把连接释放。

另外,应用层的某些协议,也有一些这样的检测机制。例如HTTP长连接中,也会定期检测对方的状态。例如QQ,在QQ断线之后,也会定期尝试重新连接。

相关推荐
REDcker3 小时前
RFC1918私有IP地址空间详解
网络协议·tcp/ip·php
Flamingˢ4 小时前
FPGA中的存储器模型:从IP核到ROM的深度解析与应用实例
网络协议·tcp/ip·fpga开发
吠品4 小时前
IP证书-SSL证书申请
网络·网络协议·tcp/ip
四月_h4 小时前
vue2项目集成websocket
网络·websocket·网络协议
坐怀不乱杯魂5 小时前
Linux网络 - UDP/TCP底层
linux·服务器·网络·c++·tcp/ip·udp
星辰徐哥5 小时前
易语言网络通信编程基础:HTTP/HTTPS/TCP/UDP实战开发
开发语言·http·https·udp·tcp·易语言
DevilSeagull5 小时前
HTTP/HTTPS数据包拓展
网络·网络协议·http·https·web渗透·we
REDcker5 小时前
HTTP 状态码清单大全
网络·网络协议·http
酣大智5 小时前
TCP与UDP协议
运维·网络·网络协议·tcp/ip