42.传输层协议TCP(一)

报文的理解

如果应用层正在进行报文的解析,处理,会不会影响OS从网络中读取报文?为什么?

不会,首先,一个进程不是要运行到退了cpu才能运行其他的进程。进程有对应的时间片,时钟中断一直在进行,cpu接受到中断,cpu转而处理OS内置的中断向量表中对应的中断处理方法,进行进程调度,检查时间片,时间片耗尽了,进程会被切换。进程切换进程task_struct会保留上下文数据,不会影响下一个进程的执行。

在OS内部,一定可能会同时存在大量的报文,而这些报文,有的在传输层,有的在网络层,OS就必须管理这些报文 -> 先描述,在组织

struct sk_buff是描述报文的结构体

head成员:指向数据区的头部

end成员:指向数据区的尾部

tail:指向应用层数据的尾部

data:指向的是****当前所在层协议报头头部。

所谓的解包和分用,本质就是移动data指针在缓冲区中的指向(****+-对应协议层报头的长度)

TCP结构

标准问题:

报头和有效载荷怎么分离?

TCP是不定长报头,其可以携带对应的选项,不带选项报头为20字节。其结构中有4位首部长度,4位比特位取值:[0,15],怎么表达20及以上字节呢?4位比特位,基本单位是4字节,能表示的字节数取值:[0,60],但由于TCP最少都是20字节,取值范围是[20,60],4位比特位取值范围[5,15]。

如何交付?16位的目的端口号

怎么没有报文大小?只有报头大小

TCP不需要也不能设置报文大小。TCP是面向字节流的,传输层只要能把报文进行解包分用传给应用层的接收缓冲区就行了,具体处理字节流,应用层怎么保证读到一个完整报文,由应用层来做。

那么既然不清楚TCP报文大小,有没有可能struct sk_buff中同时存在两个TCP报头,黏在一起了?不可能,一个struct sk_buff只存一个报文,这也是TCP不需要设置报文大小的体现。

TCP可靠性的本质

正确理解可靠性:

1)具有应答,可以保证历史消息的可靠性!(100%保证)

2)通信中,最新的报文永远没有应答,最新报文可靠性无法保证

保证可靠性,TCP核心:确认应答机制(让报文不是最新的)

确认应答理解:例如客户端向服务端发送数据,服务端必须应答,只要客户端收到了服务端的应答,就可以100%保证数据被服务端收到了。

TCP的通信过程(32位序号,32位确认序号)

客户端向服务端发送数据,服务端应答,客户端收到应答,由此可以保证客户端到服务器的可靠性。相反则可以保证服务器到客户端的可靠性(且不对应答做应答,防止无穷递归)

TCP传递报文时,更通用的过程:发送一堆请求,等待服务器应答。

TCP结构:32位序号,32位确认序号
确认序号

  • 数值:确认序号 = 序号 + 1
  • 表达意义:指定报文需要之前的所有信息,已经全部收到(下一次发送,从确认序号开始)

序号作用:排序,解决乱序问题(发送顺序和接受顺序不一致,UDP解决不了)

为什么会要有两个序号?

例如:客户端向服务器发送数据,服务器可以进行捎带应答(应答+数据),此时服务器TCP报头的序号填自己独立的,TCP确认序号为client序号+1。因为有捎带应答的情况,此时必须要有两个序号进行区分。

流量控制(16位窗口大小)

16位窗口大小含义:当前连接接收缓冲区剩余大小。

**问题:以客户端向服务端发送数据为例,客户端向服务端发送了大量数据,服务端的接收缓冲区装满了数据。客户端再向服务端发的时候,服务端已经满了。这个数据就只能被丢弃,那么tcp怎么能保证可靠性?不影响,没有收到对应的应答,重传就完了。这个做法本身没有错误,也能实现,但是问题就是这样做太耗费资源了,**费尽千辛万苦送到缓冲区,结果被丢弃了,为什么服务端不早点说接收不了呢?

16位窗口大小:表示当前连接的接收缓冲区剩余大小。通过读取这个字段,客户端就可以知道服务端的接受能力了。

流量控制:主要解决的是效率问题,接收缓冲区剩余大小大的话,就发快一点,反之发慢一点,就可以尽可能减少资源的浪费。

标志位存在意义

标志位本质:报头中的比特位

为什么要有标志位?

要有表示报文类型的字段(例如不能对应答做应答,就要区分应答和数据)。接收方收到的TCP报文,一定会存在不同的类型,针对不同报文类型,接收放要有不同的做法。

6个TCP标志位

ACK:确认号是否有效(标明报文是一个应答报文)acknowledge
SYN:同步标志位,连接建立,握手过程使用的标志位(同步报文段)。

FIN:通知对方,本端要关闭了(结束报文段)。
PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走(psh让系统调用read的条件就绪,比如read本来要500个字节才能解除阻塞,psh可以改。)

关于三次握手: 前两次握手不能携带数据,因为第三次握手没有完成!

RST:对方要求重新建立连接(复位报文段)

例如:TCP通信,客户端向服务端发起连接,三次握手后,客户端在发出去请求,收到服务端的捎带应答后,发出应答,不管这个应答有没有丢失,它都认为自己已经建立连接了。对于服务端而言,要晚一步,服务端要收到这个应答才能表明建立连接了。如果在这个过程中,客户端发送的应答丢失了,客户端还是认为自己建立好了连接,给服务端发送数据,服务端接受到对应的数据就会发送设置好RST的TCP报头,要求客户端重新建立连接。

通信的过程中,连接出现任何问题,都可以进行重置!

URG:紧急指针是否有效

tcp是保证可靠性的 -> 序号 -> 按序到达的 -> 接收缓冲区 -> 字节流式的接收队列 -> 如果我们有数据,想被优先读取(非主流),优先处理(情况:取消下载,取消上传,需要插队,不要等下载完在取消,效率低)

紧急数据,并不属于常规数据 -> 带外数据。紧急数据,只有一个字节(可用作状态码)。

16位紧急指针含义:当前报文有效载荷中,特定偏移量处,有紧急数据(一个字节)

序列号初步理解

TCP将每个字节的数据都进行了编号,即为序列号。发送缓冲区看成一个字符数组,那么发送缓冲区,每一个字节,天然不就有编号了!

理解丢包,理解应答报文

发送方没有收到ACK,意味着什么?

意味数据包丢失了吗?-> 只能意味着:数据可能丢失,对方可能没收到(例如:数据没丢丢包,ACK丢包了)

意味着:要么数据丢,要么应答丢 -> 无法100%保证对方是否收到消息,无法保证可靠性。

如何判定是真的丢包了呢?

特定的时间间隔,收不到应答,判定报文丢失! -> 收不到应答 && 超时

如果数据包没丢失,服务端收到了,但由于应答丢了,客户端超时重传了,此时数据就重复了,怎么解决?

序号的作用:确认应答,按序到达,去重

时间间隔应该是多长?

最理想的情况下,找到一个最小的时间。TCP为了保证无论在任何环境都能比较高性能地通信,因此会动态计算这个最大超时时间。

超时以500ms为一个单位进行控制,重传每次叠加,如果超过一定重传次数,依旧收不到应答,那么TCP认为网络或者对端主机出现异常,强制关闭连接。

连接管理和连接状态

状态就是整数,定义的宏值。

连接会大量存在,有的刚建立,有的已经释放,要不要管理?要,先描述,在组织struct link。

connect会发起三次握手(cilent),accept不参与三次握手(server),握手工作由OS自动完成。

如何理解accept不参与三次握手?

客户端调用connect向服务端发起连接,不需要服务端进行accept也能完成,并成功与服务端连接。accept只是把OS中已经建立好的连接(struct link)拿上来用了。

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

两个理由:

1)以最小成本,100%确认双方通信意愿

2)以最短的方式,进行验证全双工(本质验证:我们两个所处网络是通畅的,能支持全双工)

如何理解:

2)以cs举例,客户端向服务端发送SYN报头,服务端收到并捎带应答发送SYN+ACK报头,

此时客户端收到了,客户端的发送(ACK报头)和接收(收到SYN+ACK报头)就好了,服务端的接收(SYN报头)也验证了,客户端发送ACK报头,服务器到,服务端的发送能力也验证了(验证了网络通畅和双方都支持全双工)

**1)**3次握手,是成本最低的,本质也是4次握手,只不过服务端捎带应答(SYN+ACK)

面对客户端的连接请求,服务器都要无脑接受(捎带应答)

相关推荐
阿方索2 小时前
DHCP 服务器
linux·运维
春夜喜雨2 小时前
linux下如何检查与设置程序与服务崩溃时生成coredump文件--包括systemctl启动的服务
linux
小狗爱吃黄桃罐头3 小时前
正点原子【第四期】Linux之驱动开发学习笔记-6.1 pinctrl和gpio子系统
linux·驱动开发·学习
小心草里有鬼3 小时前
Linux 数据库 Mysql8 主从复制
linux·运维·数据库·sql·mysql
czhc11400756633 小时前
Linux925 shell 变量:本地、环境变量、全局变量;数组:普通数组、关联数组;交互定义、basename、dirname
linux·交互
chen_note3 小时前
Keepalived两个集群实验
linux·服务器·数据库·keepalived·高可用集群
Akshsjsjenjd3 小时前
HAProxy 使用指南:从基础到实战部署
linux·负载均衡
東雪蓮☆4 小时前
ELK 企业级日志分析系统实战教程
linux·运维·elk
泽虞5 小时前
《C++程序设计》笔记p4
linux·开发语言·c++·笔记·算法