TCP 协议

目录

1.TCP协议段格式

2.TCP原理

1.确认应答机制(安全机制)

2. 超时重传机制(安全机制)

3.连接管理机制(安全机制)

4.滑动窗口(效率机制)

5.流量控制(安全机制)

6.拥塞控制(安全机制)

 7.延迟应答(效率机制)

8.捎带应答(效率机制)

3.其他特性

1.面向字节流

2.缓冲区

3.大小限制

4.粘包问题

如何避免粘包问题呢?

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

5.TCP异常情况

1.TCP协议段格式

  • /目的端口号:表示数据是从哪个进程来,到哪个进程去;
  • 4TCP报头长度:表示该TCP头部有多少个32bit(有多少个4字节);所以TCP头部最大长度是15 * 4 = 60
  • 6位标志位:  boolean值,0/1数据

ACK:应答;确认号是否有效

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

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

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

FIN:申请断开连接;通知对方,本端要关闭了,我们称携带FIN标识的为结束报文段

2.TCP原理

TCP 对数据传输提供的管控机制,主要体现在两个方面: 安全和效率
这些机制和多线程的设计原则类似:保证数据传输安全的前提下,尽可能的提高传输效率。(TCP是综合考虑了两者,取的一个均衡:不是保证绝对意义的可靠,也不是绝对意义的效率最高)

1.确认应答机制(安全机制)

数据:TCP将每个字节的数据都进行了编号,并使用32位序号保存,即为序列号。

确认应答:ACK标志位置为1,会使用32位确认序号保存

下一个是多少?

接收到的数据报,连续序号的最大值+1

隐藏含义:接收端下一个的序号,告诉发送者之前的数据报,全部都接收到了

2. 超时重传机制(安全机制)

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

因此主机B会收到很多重复数据。那么TCP协议需要能够识别出那些包是重复的包,并且把重复的丢弃掉。

3.连接管理机制(安全机制)

在正常情况下,TCP要经过三次握手建立连接,四次挥手断开连接。

 建立连接:本质是双方保存了一个连接状态

  1. 客户端发送syn => 申请建立客户端到服务端的连接
  2. 服务端返回syn + ack => 申请建立服务端到客户端的连接(syn和ack可以合并一起发送,也可以分开发)
  3. 客户端返回ack => 对第二个数据报syn的应答

断开连接

  1. 客户端发送fin到服务端:申请关闭客户端到服务端的连接
  2. 服务端返回ack => 服务端状态置为 close_wait
  3. 服务端发送fin到客户端:申请关闭服务端到客户端的连接 => 客户端接收到,状态置为time_wait
  4. 客户端返回ack => 服务端状态置为closed(已关闭)                                                                                             => 客户端等待一定时间,状态置为closed(已关闭)

客户端接收到第三个数据报,不能马上置为closed

原因:第四个数据报可能出现丢包(服务器无法断开连接),服务端就会根据超时重传机制,               重发第三个数据报,此时客户端如果是closed,就没法接受

服务端状态转化:

  • [CLOSED -> LISTEN] 服务器端调用listen后进入LISTEN状态,等待客户端连接;
  • [LISTEN -> SYN_RCVD] 一旦监听到连接请求(同步报文段),就将该连接放入内核等待队列中,并向客户端发送SYN确认报文。
  • [SYN_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] 服务器收到了对FINACK,彻底关闭连接。
客户端状态转化:
  • [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] 客户端要等待一个2MSLMax Segment Life,报文最大生存时间)的时间,才会进入CLOSED状态。

下图是TCP状态转换的一个汇总:

  • 较粗的虚线表示服务端的状态变化情况;
  • 较粗的实线表示客户端的状态变化情况;
  • CLOSED是一个假想的起始点,不是真实状态;

 问题一:双方的连接状态,为什么最后才是closed?

答:双方都要保证可靠的关闭连接

问题二:第二、三个数据报为什么没有合并?

答:第二个数据报,是系统内核返回的(不用程序写代码来发送)

       第三个数据报,是程序调用closed方法发送的

问题三:服务器中出现大量closed_wait的原因?

答:服务端没有执行close方法(因为执行close才会发送第三个数据报)

4.滑动窗口(效率机制)

作用:以并行的方式发送数据报,减少等待时间,提高效率

  • 窗口大小指的是无需等待确认应答而可以继续发送数据的最大值。上图的窗口大小就是4000 个字节(四个段)。
  • 发送前四个段的时候,不需要等待任何ACK,直接发送;
  • 收到第一个ACK后,滑动窗口向后移动,继续发送第五个段的数据;依次类推;
  • 操作系统内核为了维护这个滑动窗口,需要开辟 发送缓冲区 来记录当前还有哪些数据没有应答;只有确认应答过的数据,才能从缓冲区删掉;
  • 窗口越大,则网络的吞吐率就越高;

 发生的丢包的情况:

  1. ack丢包:没影响,后续的ack也能表示序号前的全部接收
  2. 发送的数据报丢包:接收的ack下一个序号是接收端,接收到的连续序号最大值+1(如果中间有部分没接收到,就相当于不连续)                                                                                            快重传:连续三次接收到下一个是x,就表示从x开始的数据报丢包,需要重传

5.流量控制(安全机制)

接收端处理数据的速度是有限的。如果发送端发的太快,导致接收端的缓冲区被打满,这个时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应。
因此 TCP 支持根据接收端的处理能力,来决定发送端的发送速度。这个机制就叫做 流量控制( Flow Control
  • 接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 "窗口大小" 字段,通过ACK端通知发送端;
  • 窗口大小字段越大,说明网络的吞吐量越高;
  • 接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端;
  • 发送端接受到这个窗口之后,就会减慢自己的发送速度;
  • 如果接收端缓冲区满了,就会将窗口置为0;这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端。

6.拥塞控制(安全机制)

TCP 引入 慢启动 机制,先发少量的数据,探探路,摸清当前的网络拥堵状态,再决定按照多大的速度传输数据;

  • 此处引入一个概念程为拥塞窗口
  • 发送开始的时候,定义拥塞窗口大小为1
  • 每次收到一个ACK应答,拥塞窗口加1
  • 每次发送数据包的时候,将拥塞窗口和接收端主机反馈的窗口大小做比较,取较小的值作为实际发送的窗口;

  • TCP开始启动的时候,慢启动阈值等于窗口最大值;
  • 在每次超时重发的时候,慢启动阈值会变成原来的一半,同时拥塞窗口置回1
少量的丢包,我们仅仅是触发超时重传;大量的丢包,我们就认为网络拥塞;
TCP 通信开始后,网络吞吐量会逐渐上升;随着网络发生拥堵,吞吐量会立刻下降;
拥塞控制,归根结底是 TCP 协议想尽可能快的把数据传输给对方,但是又要避免给网络造成太大压力的折中方案。

 7.延迟应答(效率机制)

 接收端返回流量窗口代表接收缓冲区的可用空间大小,如果立即返回,就不划算

 接收端返回的流量窗口,不是立即返回,而是等待一定时间,这样返回的流量窗口大小就可能更大

8.捎带应答(效率机制)

 不管是客户端还是服务端,接收到数据后,返回的ack应答包(作为接收端),可以和发送的数据报(作为发送端)再一起(捎带的方式)发送给对方

3.其他特性

1.面向字节流

2.缓冲区

3.大小限制

4.粘包问题

  • 首先要明确,粘包问题中的 "" ,是指的应用层的数据包。
  • TCP的协议头中,没有如同UDP一样的 "报文长度" 这样的字段,但是有一个序号这样的字段。
  • 站在传输层的角度,TCP是一个一个报文过来的。按照序号排好序放在缓冲区中。
  • 站在应用层的角度,看到的只是一串连续的字节数据。
  • 那么应用程序看到了这么一连串的字节数据,就不知道从哪个部分开始到哪个部分,是一个完整的应用层数据包。

如何避免粘包问题呢?

归根结底就是一句话, 明确两个包之间的边界
  • 对于定长的包,保证每次都按固定大小读取即可;例如上面的Request结构,是固定大小的,那么就从缓冲区从头开始按sizeofRequest)依次读取即可;
  • 对于变长的包,可以在包头的位置,约定一个包总长度的字段,从而就知道了包的结束位置;
  • 对于变长的包,还可以在包和包之间使用明确的分隔符(应用层协议,是程序猿自己来定的,只要保证分隔符不和正文冲突即可);

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

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

5.TCP异常情况

进程终止:进程终止会释放文件描述符,仍然可以发送 FIN 。和正常关闭没有什么区别。
机器重启:和进程终止的情况相同。
机器掉电 / 网线断开:接收端认为连接还在,一旦接收端有写入操作,接收端发现连接已经不在了,就会进行reset 。即使没有写入操作, TCP 自己也内置了一个保活定时器,会定期询问对方是否还在。如果对方不在,也会把连接释放。
另外,应用层的某些协议,也有一些这样的检测机制。例如 HTTP 长连接中,也会定期检测对方的状态。 例如QQ ,在 QQ 断线之后,也会定期尝试重新连接。
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值