0
点赞
收藏
分享

微信扫一扫

阿赵UE学习笔记——19、IK重定向流程

诗远 03-21 06:00 阅读 3

目录

netstat

pidof

UDP协议

TCP协议

TCP协议段格式

TCP协议的相关机制

确认应答(ACK)机制

超时重传机制

连接管理机制

服务端状态转换 

客户端状态转化

流量控制

 流量控制常见问题:

滑动窗口 

拥塞控制

延迟应答

面向字节流

粘包问题

TCP异常情况


传输层的作用就是负责数据能够从发送端接收数据

端口号

端口号(Port)标识了一个主机上进行通信的不同应用程序;

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

端口号范围的划分

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

认识知名端口号

有些服务器是非常常用的 , 为了使用方便 , 人们约定一些常用的服务器 , 都是用以下这些固定的端口号 :

执行下面的命令,可以看到知名端口号

两个问题

  • 一个进程是否可以bind多个端口号?
  • 一个端口号是否可以被多个进程bind?

netstat

 netstat是一个用来查看网络状态的重要工具

pidof

UDP协议

UDP协议端格式

TCP协议

        TCP全称为 "传输控制协议(Transmission Control Protocol"). 人如其名, 要对数据的传输进行一个详细的控制; 

TCP协议段格式

4位的首部长度描述的报头的长度,计算的时候,有基本的大小单位:4字节 

例如 x*4=20 ,x取5 也就是0101

如果不进行流量控制,会导致大面积丢包 

16位窗口大小就是对方接收缓冲区剩余空间,也就是进行流量控制的依据

tcp协议不同于http协议的是双方都会进行收发数据

TCP最基本、最原始的通信过程

        收到应答信号,确认最近发送的信息对方收到了,没有应答的数据,我们无法保证可靠性,所以,最新的一条信息,是没有应答的,所以我们无法保证发出去的信息是100%可靠的。

综上,世界上是不存在100%可靠的网络协议,但是局部性的可靠性是可以保证的。

一段时间后,如果没有收到应答,就认为数据丢失了,进行重传。

将应答和下一个TCP数据二合一发送给对方,这种策略称为捎带应答

乱序问题

那么接下来有一个问题,如果客户端发送tcp数据给服务器,服务器没有返回应答信号,客户端是否继续发送下一条数据?

如果采用发一条数据,应答一个的方式,效率会很低,因此客户端一般一次给服务器发送一批数据

服务器数据的接收顺序并不一定是客户端发送数据的顺序 ,这种问题称为数据包乱序问题。这种情况如果不解决,直接将数据交到缓冲区,会导致应用层解析数据报文错误。造成乱序本身就是不可靠的一种。

为了解决这种问题,引入序号,给每个报文加上序号,发送到服务端,即使服务端收到的是乱序的,也可以通过序号进行还原。

如下图所示:

综上,也就是说32位序号是为了保证数据的按序到达

 服务端接收到客户端的一批tcp数据后,会返回多个应答数据,那么怎么区分某个应答是对应哪个tcp数据呢?

确认序号:填充的是它收到的报文的序号+1

为什么要这么规定?

确认序号的意义:表示确认序号之前的数据,已经全部收到了,下一次发送,请从确认序号指定的数字开始发送!!

当应答返回3001,而2001、1001未返回相应应答 ,服务端默认3001之前已经全部收到了,这样的规定允许应答能有少量的丢失。

tcp收到的报文一定是由各种“类型”的,不同的类型,决定了服务端做不同的动作!接收方如何得知报头的类型是什么?用6个标记位,标记位存在的意义:区分tcp报文的类型

ACK :确认序号是否有效

SYN:请求建立连接,我们把携带SYN标识的称为同步报文段

FIN:通知对方,本端要关闭了

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

RST:对方要求重新建立连接,我们把携带RST标识的称为复位报文段

URG:紧急指针是否有效

16位紧急指针:当前报文包含紧急数据的偏移量是多少,紧急数据为一个字节,称为带外数据,缓冲区排队的数据是常规数据

三次握手

TCP协议的相关机制

综上所述,我们可以总结出TCP协议的几个机制:

确认应答(ACK)机制

TCP将每个字节的数据都进行了编号,即为序列号,每个ACK都带有对应的确认序列号,意思是告诉发送者,我已经收到了哪些 数据,下次你从哪里开始发

超时重传机制

  • 主机A发送数据给B之后,可能因为网络拥堵等原因,数据无法到达主机B;
  • 如果主机A在一个特定时间间隔内没有收到B发来的确认应答,就会进行重发。 

但是主机A未收到B的确认应答,也可能是ACK丢失了。

        因此主机B 会收到很多重复数据 . 那么 TCP 协议需要能够识别出那些包是重复的包 , 并且把重复的丢弃掉 . 这时候我们可以利用前面提到的序列号, 就可以很容易做到去重的效果 .

连接管理机制

服务端状态转换 

[CLOSED -> LISTEN] 服务器端调用listen后进入LISTEN状态,等待客户端连接。

[LISTEN -> SYS_RCVD] 一旦监听到连接请求(同步报文段SYN),就将该连接放入内核等待队列中,并向客户端发送SYN确认报文

[SYS_RCVD -> ESTABLISHED] 服务端一旦收到客户端的确认报文,就进入ESTABLISHED,可以进行读取数据

 [ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭连接(调用close),服务器会收到结束报文段,服务器返回确认报文段并进入CLOSE_WAIT;

[CLOSE_WAIT -> LAST_ACK] 进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据); 当服务器真正调用close关闭连接时, 会向客户端发送FIN, 此时服务器进入LAST_ACK状态, 等待最后一个 ACK到来(这个ACK是客户端确认收到了FIN)

[LAST_ACK -> CLOSED] 服务器收到了对FIN的ACK, 彻底关闭连接

客户端状态转化

[CLOSED -> SYN_SENT] 客户端调用connect, 发送同步报文段;

[SYN_SENT -> ESTABLISHED]  connect调用成功, 则进入ESTABLISHED状态, 开始读写数据;

[ESTABLISHED -> FIN_WAIT_1] 客户端主动调用close时, 向服务器发送结束报文段, 同时进入

FIN_WAIT_1;

[FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认, 则进入FIN_WAIT_2, 开始等待服务器的结束报文段;

[FIN_WAIT_2 -> TIME_WAIT] 客户端收到服务器发来的结束报文段, 进入TIME_WAIT, 并发出LAST_ACK;

[TIME_WAIT -> CLOSED] 客户端要等待一个2MSL(Max Segment Life, 报文最大生存时间)的时间, 才会进入CLOSED状态.

PS:listen的第二个参数?backlog+1,表示底层已经建立好的连接队列的最大长度

全连接队列的大小为什么不能太长?

为什么不能没有全连接队列?

一个网络报文在网络里存活的时间称为MSL

TIME_WAIT:等多长时间,为什么?

流量控制

        接收端处理数据的速度是有限的. 如果发送端发的太快 , 导致接收端的缓冲区被打满 , 这个时候如果发送端继续发送 , 就会造成丢包, 继而引起丢包重传等等一系列连锁反应 . 因此TCP 支持根据接收端的处理能力 , 来决定发送端的发送速度 . 这个机制就叫做 流量控制 (Flow Control);    

接收端如何把窗口大小告诉发送端呢 ? 回忆我们的 TCP 首部中 , 有一个 16 位窗口字段 , 就是存放了窗口大小信息 ;

那么问题来了 , 16 位数字最大表示 65535, 那么 TCP 窗口最大就是 65535 字节么 ?

实际上 , TCP 首部 40 字节选项中还包含了一个窗口扩大因子 M, 实际窗口大小是 窗口字段的值左移 M ;

这个窗口扩大因子选项如下图所示:

 流量控制常见问题:

滑动窗口 

滑动窗口是我们发送端缓冲区的一部分。至于区域划分可以理解成通过双指针(下标)进行区分即可。

滑动窗口的大小,不能超过对方的接收缓冲区的剩余空间的大小,即应答报文的窗口大小

情况1:如果丢包了,怎么理解滑动窗口

        如果我们成功发送2001之前的报文,也得到了接收方返回的ACK报文,3001位置发生丢包,4001,5001得到了接收方返回的ACK报文,我们在进行窗口滑动时,会在2001位置停下来,等待3001位置进行重发得到ACK报文,在加上之前我们对确认序号的定义:确认序号是x,x之前的报文我们全部都收到了,综上保证了滑动窗口连续的向后更新,不会出现跳跃的情况,也就是跳过丢包的报文。

情况2:数据包直接丢了

发送方连续三次收到同样的确认应答时则进行重发,这种方式称为快重传 。

已经有了快重传,为什么还要有超时重传?

问题2:滑动窗口可以向左移动吗?会向右移动吗?移动的时候,大小会变化吗?怎么变化?会为0吗?

问题3:滑动窗口会在发送缓冲区越界吗?

拥塞控制

如果发送数据,出现问题,不仅仅是对方主机出现问题,也有可能是网络出现问题

  1. 如果通信的时候,出现少量的丢包(常规情况)
  2. 如果通信的时候,出现大量的丢包(网络出现了问题)
  • 硬件设备出现问题
  • 数据量太大,引起阻塞

如果通信双方出现了大量的数据丢包问题(滑动窗口内大量的数据都超时了),tcp会判断网络出现问题了(网络拥塞了)

我们发送方应该怎么办?我们不能立即对报文进行超时重发,否则会加重网络拥塞。

延迟应答

如果接收数据的主机立刻返回 ACK 应答 , 这时候返回的窗口可能比较小 .

  • 假设接收端缓冲区为1M. 一次收到了500K的数据; 如果立刻应答, 返回的窗口就是500K;
  • 但实际上可能处理端处理的速度很快, 10ms之内就把500K数据从缓冲区消费掉了;
  • 在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来;
  • 如果接收端稍微等一会再应答, 比如等待200ms再应答, 那么这个时候返回的窗口大小就是1M;

一定要记得 , 窗口越大 , 网络吞吐量就越大 , 传输效率就越高 . 我们的目标是在保证网络不拥塞的情况下尽量提高传输效率;

那么所有的包都可以延迟应答么 ? 肯定也不是 ;

  • 数量限制: 每隔N个包就应答一次;
  • 时间限制: 超过最大延迟时间就应答一次;

具体的数量和超时时间 , 依操作系统不同也有差异 ; 一般 N 2, 超时时间取 200ms;

面向字节流

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

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

由于缓冲区的存在 , TCP 程序的读和写不需要一一匹配 , 例如 :

  • 100个字节数据时, 可以调用一次write100个字节, 也可以调用100write, 每次写一个字节;
  • 100个字节数据时, 也完全不需要考虑写的时候是怎么写的, 既可以一次read 100个字节, 也可以一次read一个字节, 重复100;

粘包问题

面向字节流衍生出来的问题,接收一个半或者半个(不完整的报文);

如何解决用户层的粘包问题?

  1. 定长报文:在应用层通过自定义协议,明确报文和报文之间的边界
  2. 使用特殊字符
  3. 使用自描述字段+定长报头
  4. 使用自描述字段+特殊字符

对于UDP协议来说, 是否也存在 "粘包问题" ?

  1. 对于UDP, 如果还没有上层交付数据, UDP的报文长度仍然在. 同时, UDP是一个一个把数据交付给应用层. 就有很明确的数据边界.
  2. 站在应用层的站在应用层的角度, 使用UDP的时候, 要么收到完整的UDP报文, 要么不收. 不会出现"半个"的情况。

TCP异常情况

1)进程终止

连接正常自动断开,因为tcp连接是和文件直接相关的,文件的生命周期是随进程的。

2)机器重启

先杀掉所有的进程

3)机器掉电/网线断开

举报

相关推荐

0 条评论