传输层协议——TCP

TCP全称为“传输控制协议”人如其名,要对数据的传输进行一个详细的控制

TCP协议段格式

在这里插入图片描述
1、源/目的端口:表示数据从哪个进程来,到哪个进程去。
2、4位TCP报头的长度:表示该TCP头部有多少个32位bit(有多少个4字节); 所以TCP头部最大长度是15 * 4 = 60
3、6位标志位:

URG: 紧急指针是否有效
ACK: 确认号是否有效
PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走
RST: 对方要求重新建立连接; 我们把携带RST标识的称为复位报文段
SYN: 请求建立连接; 我们把携带SYN标识的称为同步报文段
FIN: 通知对方, 本端要关闭了, 我们称携带FIN标识的为结束报文段

4、16位校验和: 发送端填充, CRC校验. 接收端校验不通过, 则认为数据有问题. 此处的检验和不光包含TCP首部, 也
包含TCP数据部分.
5、16位紧急指针: 标识哪部分数据是紧急数据;

TCP特点

1、有连接
2、可靠

1、数据没有出现错误。(通过校验和来保证)
2、确保发送的数据,对方有收到,并且发送方知道对方有收到。(通过ACK)
3、如果对方收到重复的数据,可以根据序号(SN)去重。(通过SN)
4、去报发送的数据对方是按序(发送的顺序)收到的。(通过SN)

3、面向字节流

TCP中有很多机制来保证高效可靠的通信

确认应答机制(ACK)

在这里插入图片描述
TCP将每个字节数据都进行了编号(序号)
每一个ACK都带有对应的确认序列号,目的告诉发送者,我已经收到了哪些数据,下一次从哪里开始发。
如果发送端收到确认应答,说明数据已经成功到达对端,反之,数据丢失的可能性很大。

超时重传机制

如果发送端没有收到接收端发送的确认应答,可能是传输过程中出现了丢包现象。

(1)可能是传输数据时数据包丢掉导致主机B没有收到数据,也没有发送确认应答;此时一段时间内主机A都为收到确认应答,就会对此数据进行重发。
在这里插入图片描述
(2)也有可能是主机B发送确认应答的过程中发生丢包,ACK丢失,主机A没有收到确认应答;此时一段时间内主机A都为收到确认应答,就会对此数据进行重发。
在这里插入图片描述
因为ACK的丢失导致主机A没有收到确认应答,主机A会重复给主机B发送数据,这就会导致主机B收到很多重复的数据。TCP可以通过序号(SN)将重复的去掉。

SN的作用:
1、确保接收方按序收到(在接缓冲区按序号做排序)
2、去掉重复的数据
发送缓冲区:
保存已发送但还未收到确认应答的数据
接受缓冲区:
1、保存还未被应用程序读走的数据
2、保存无序到达的数据,在接收缓冲区进行排序

如何确定超时的时间?
1、Linux中(DSB Unix和Windows也是如此),超时以500ms为一个单位进行控制,每次判定超时重发的超时时间都是500ms的整数倍
2、如果重发一次之后,任然得不到应答,等待2500ms后在进行重传
3、如果任然得不到应道,等待4
500ms,依次类推,以指数形式递增
4、累积到一定的重传次数,TCP认为网络或者对端主机出现异常,强制关闭

TCP的连接管理——可靠性为基础

TCP提供面向有连接的通信传输,面向有连接是指在数据通信开始之前先做好通信两端之间的准备工作。确认通信双方都可收发数据。
在这里插入图片描述

三次握手建立连接

服务器端处于监听状态
第一次握手: 客户端主动建立连接,客户端向服务器发送一个SYN包(表示主动建立连接),并且进入SYN_SET状态,等待服务器进行确认。
第二次握手: 服务器收到客户端的SYN包,确认应答客户的SYN(ACK=1),并且自己也发送一个SYN包此时服务器,此时服务器进入了SYN_RECV状态。
**第三次握手:**客户端收到服务器的SYN+ACK包,向服务器发送确认应答包ACK,发送完毕之后,客户端部和服务器部进入ESTABLELISHED状态,完成三次握手。开始传送数据。

三次握手的原因:
首先TCP是是双向通信协议,即双方都可以发送信息,并接受信息。TCP采用三次握手是为了实现可靠
数据的传输,它的过程就是通信双方相互告知各自序列号的起始值,(这里是因为序列号的初始值是
随机的,如果都是0的话就不用了同步了,但是如果初始序列号是确定的话,就会被伪造的segement
进行攻击)并确认对方已经收到了序列号的起始值的必经步骤。如果是两次握手,只有连接发起方的
其实序列号能被确认,另一方的序列号不能被确认。如果服务端在向客户端发送SYN+ACK时丢包了,
但是服务端根本不知道什么情况。就不能同步服务端的序列号了。
四次挥手断开连接

第一次:主机A的应用程序通知TCP数据已经发送完毕时,TCP向主机B发送一个FIN标记的报文段,并且进入FIN-WAIT1状态。
第二次:主机B收到响应给A 一个确认报文ACK,此时A进入了FIN-WAIT2状态,B进入CLOSED-WAIT状态,但连接并未释放B会通知应用进程结束A到B方向的连接,此时TCP处于半关闭状态。(先发送ACK的目的是为了防止在这段时间内超时重传,对方重重传FIN)
第三次:当B也准备释放连接的时候就向A发送连接终止报文(带FIN标记的报文段),之后B进入LAST-WAIT状态。
第四次:A收到接受终止报文后还要再进行一次确认,发送完ACK后进入TIME-WAIT状态,等待2MSL后进入CLOSED状态,B收到该确认后进入CLOSED状态,服务器端会稍早于客户端释放连接。

等待2MSL的原因:保证被动连接方可以进入CLOSED状态。MSL是最大报文段寿命等待2MSL可以保证
A发送的最后一个确认报文被B接收,如果该报文丢失,B会超时重传之前的FIN报文,而如果A在发送
确认报文后立即释放连接,就无法收到B超时重传的报文,B无法正常进入CLOSED状态。
2MSL时间后,本连接中所有报文都会从网络中消失,防止已失效连接的请求数据报与正常连接的请求
数据报混淆而发生异常。
CLOSED_WAIT:一般而言对于服务器上出现大量的 CLOSE_WAIT 状态, 原因就是服务器没有
正确的关闭 socket, 导致四次挥手没有正确完成. 这是一个 BUG. 只需要加上对应的close
即可解决问题。
可以查看状态
netstat -nao | findstr LISTEN

在这里插入图片描述

滑动窗口

TCP以一个端为单位,没发一个段进行一次确认应答的处理,如图所示这样一个传输方式有一个缺点:包的往返时间越长,通信性能就越低。
在这里插入图片描述
TCP引入窗口概念可以解决该问题,确认应答不在是以每个分段,而是以更大的单位进行确认,也就是说,发送端主机,在发送了一个段以后不必要一直等待确认应答,而是继续发送。
在这里插入图片描述
窗口的大小指的是无需等待确认应答而可以继续发送数据的最大值。
例如上图窗口大小为4个段
在这里插入图片描述

滑动窗口机制:

在窗口内的数据即使没有收到确认应答也可以发送数据出去。
在滑动窗口以外的部分包括尚未发送的数据以及已经确认对端已经收到的数据,当数据发送后若如期收到确认应答可以不进行重发,此时数据可以从缓存区清除。
收到确认应答的情况下,将窗口滑动到确认应答序列号的位置,这样可以顺序的将多个短同时发送,提高通信性能。

在滑动窗口中出现报文丢失:

(1)确认应答报文段丢失:
在未使用串口控制的时候没收到确认应答的数据会重新发送。
该种情况数据已经发送到对端,不需要进行重发。
但使用窗口控制机制时没有确认应答的数据也无需重新发送。继续下一段数据的发送。

在这里插入图片描述
(2)数据报文丢失:
如图当1001-2000的数据段丢失后,发送端一致收到序号为1001的确认应答,这个确认应答好像是在提醒发送端“我想接受的是从1001开始的数据”。因此,在窗口比较大,有出现报文段丢失的情况下,同一个序号的确认应答将会被重复不断地返回。而发送端主机如果连续3次收到同一个确认应答,就会将其锁对应的数据进行重发。这种机制比之前提到的超时管理更加高效,因此被称为告诉重发控制。
在这里插入图片描述

流量控制

接收端处理数据的速度是有限的,如果发送端发的太快,导致接收端的缓冲区被打满,这时候如果发送端再继续发送,就会造成丢包,进而引起丢包重传等等一系列连锁反应。
因此,TCP提供了一种机制可以让发送端根据接收端的处理能力控制发送的速度。这个机制叫做流量控制。

1)接收端将自己可以接受的缓冲区大小放入TCP首部中的“窗口大小”字段,通过ACK段通知发送端
(2)窗口大小字段越大,说明网络吞吐量越高
(3)接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端
(4)发送端接收到这个窗口后就会减慢自己的发送速度
(5)如果接收端缓冲区满了,就会将窗口置为0;这时发送方不再发送数据,但需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉给发送端

在这里插入图片描述

拥塞控制

TCP有了滑动窗口机制就能高效可靠的发送大量的数据,但是如果在刚开始阶段就发送大量的数据,也可能会引发其他问题:
因为网络上有很多计算机,可能当前的网络状态就已经比较拥堵,在不清楚网络状态下,贸然发送大量数据,是很有可能引起雪上加霜的。
TCP引入慢启动机制,先发送少量的数据,探探路,摸清当前网络拥堵状态,再决定按照多大的速度传输数据。
在这里插入图片描述

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

像上面这样的拥塞窗口增长速度是指数级别的。“慢启动”知识值初始时满,但增长速度非常快。

为了不增长的那模块,因此不能使用拥塞窗口单纯的加倍
此处引用一个叫慢启动的阈值
当拥塞窗口超过这个阈值的时候,不再按照指数方式增长,而是按照线性方式增长

在这里插入图片描述
少量的丢包,我们仅仅是触发超时重传;
大量的丢包,我们就认为网络拥塞。
当TCP通信开始后, 网络吞吐量会逐渐上升; 随着网络发生拥堵, 吞吐量会立刻下降;
拥塞控制, 归根结底是TCP协议想尽可能快的把数据传送给对方,但又要避免网络造成太大压力的折中方案。

延迟应答

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

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

一定要记得,**窗口越大,网络吞吐量就越大,传输效率也就越高,**我们的目标是保证在网络不用色的情况在尽量提高传输效率。

延迟应答的两个限制:
(1)数量限制:每隔N个包就应答一次;
(2)时间限制:超过最大延时时间就应答一次

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

捎带应答

在延迟应答的基础上, 我们发现, 很多情况下, 客户端服务器在应用层也是 “一发一收” 的. 意味着客户端给服务器说了"How are you", 服务器也会给客户端回一个 “Fine, thank you”;那么这个时候ACK就可以搭顺风车, 和服务器回应的 “Fine, thank you” 一起回给客户端。

面向字节流

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

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

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

100个字节数据时, 可以调用一次write写100个字节, 也可以调用100次write, 每次写一个字节;100个字节数据时, 也完全不需要考虑写的时候是怎么写的, 既可以一次read 100个字节, 也可以一次read一个字节, 重复100
粘包问题
1)首先要明确, 粘包问题中的 "包" , 是指的应用层的数据包.2)在TCP的协议头中, 没有如同UDP一样的 "报文长度" 这样的字段, 但是有一个序号这样的字段.3)站在传输层的角度, TCP是一个一个报文过来的. 按照序号排好序放在缓冲区中.4)站在应用层的角度, 看到的只是一串连续的字节数据.5)那么应用程序看到了这么一连串的字节数据, 就不知道从哪个部分开始到哪个部分, 是一个完整的应用层数据包.

那么如何避免粘问题呢?归根结底就是一句话,明确两个包之间的边界

1)对于定长的包, 保证每次都按固定大小读取即可;2)从头开始按sizeof(Request)依次读取即可;3)对于变长的包, 可以在包头的位置, 约定一个包总长度的字段, 从而就知道了包的结束位置;4)对于变长的包, 还可以在包和包之间使用明确的分隔符(应用层协议, 是程序猿自己来定的, 只要保证分隔符不和正文冲突即可。

那么对于UDP协议来说, 是否也存在 “粘包问题” 呢?

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

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

基于TCP应用层协议

HTTP
HTTPS
SSH
Telent
FTP
SMTP

以上内容总结自图解TCP_IP

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值