TCP协议

TCP,即Transmission Control Protocol,传输控制协议。人如其名,要对数据的传输进行一个详细的控制。

TCP协议的特点:有连接,可靠传输,面向字节流,全双工

有连接:TCP协议使用时必须先建立 TCP 连接。在传送数据完毕后,必须释放已经建立的 TCP 连接。

可靠传输:可靠传输就是数据传输过去之后,发送方知道数据发送的成功与否,如果失败会尝试再次发送

面向字节流:应用层交给TCP的报文,整个报文可能会被操作系统分组成多个的 TCP 报文,也就是一个完整的TCP报文被拆分成多个 TCP 报文进行传输

例如用TCP传输100个字节的数据:如果发送端一次发送100个字节,那么接收端可能会循环接收10次,每次接收10个字节。

全双工:TCP允许通信双方的应用进程在任何时候都能发送数据

可靠传输原理:

1、确认应答机制(可靠机制):每次发送数据之后,通过收没收到回复报文来确定发送成功与否,这样传输就变得可靠了,回复的报文称之为"应答报文",也称之为"ack报文"

接收方成功接收数据的话,会向发送方发送一个应答报文表示数据成功接收,应答报文中的标志位ACK就会被置为1(之前为0),表示数据成功接收了。并且应答报文中还会携带确认序号,意思是告诉发送者,我已经收到了哪些数据;下一次你从哪里开始发。

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

 但是,主机A未收到B发来的确认应答,也可能是因为ACK丢失了;因此主机B会收到很多重复数据。那么TCP协议需要用到序列号识别出那些包是重复的包,并且把重复的丢弃掉。

超时重传的时间间隔是会逐渐变大的(因为连续的超时重传是极小概率事件),如果重传一定次数之后仍然无法传输,就会尝试重置TCP连接(断开重连),如果还是连不上,此时就直接释放连接(彻底放弃)

3、连接管理机制(可靠机制):在正常情况下,TCP要经过三次握手建立连接,四次挥手断开连接

三次握手图示:

ACK和SYN都是系统内核负责的,会在收到请求之后,立即就返回

 

三次握手的意义:检查一下当前网络情况是否畅通、检查通信双方的发送能力和接收能力是否正常、协商一些重要参数

四次挥手图示:

ACK是系统内核负责的,会在收到请求之后,立即就返回,而FIN是应用程序负责的(代码中主动调用close),取决于我们的代码

 

 

4、滑动窗口(效率机制):TCP希望能够在保证可靠性的前提下,尽可能的提高传输效率,因此可以使用滑动窗口来提升效率

滑动窗口:每次批量发送一波数据,然后再等一波ACK,再发一波数据。我们把每次批量发送的数据的量称之为"窗口大小"~~

注意:接收方是收到一个数据就发送一个ACK,而不是等所有数据都到了才统一发下一组;发送方也是收到一个ACK就继续发一条数据,而不是等所有ACK都到了才统一发下一组~~

 白色窗口就表示哪些数据在等待确认,也就是在等待数据到达与接收应答报文这个过程准确无误的完成:

 

情况一:数据包已经抵达,ACK被丢了。

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

 

情况二:数据包就直接丢了。

当某一段报文段丢失之后,发送端会一直收到 1001 这样的ACK,就像是在提醒发送端 "我想要的是 1001" 一样

如果发送端主机连续三次收到了同样一个 "1001" 这样的应答,就会将对应的数据 1001 - 2000 重新发送;

这个时候接收端收到了 1001 之后,再次返回的ACK就是7001了(因为2001 - 7000)接收端其实之前就已经收到了

这种机制被称为 "快速重传机制",它是搭配了滑动窗口机制的"超时重传"。

 

5、流量控制(可靠机制):在滑动窗口的基础之上,对发送速率做出限制的机制,也就是限制发送方的窗口大小不要太大(要合适)

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

接收方使用接收缓冲区的剩余空间大小,来作为发送方发送速率(窗口大小)的参考数值

接收方将自己可以接收的缓冲区大小放入 TCP 首部中的 "窗口大小" 字段,通过ACK通知发送方;

接收方一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送方;发送方接受到这个窗口之后,就会减慢自己的发送速度;

如果接收方缓冲区满了,就会将窗口置为0;这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,使接收方把窗口大小告诉发送方。

 

6、拥塞控制(可靠机制):也在滑动窗口的基础之上,对发送速率做出限制的机制,也就是限制发送方的窗口大小不要太大(要合适)

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

每次发送数据包的时候,将拥塞窗口和接收端主机反馈的窗口大小(也就是和流量控制)做比较,取较小的值作为实际发送的窗口

 

7、延迟应答(效率机制):

延迟应答的作用就是让窗口大小在不影响接收方与发送方的处理能力的前提下尽量的大一些

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

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

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

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

数量限制:每隔N个包就应答一次;

时间限制:超过最大延迟时间就应答一次;

 8、捎带应答(效率机制):本来ACK是系统内核负责的,会在收到请求之后,立即就返回,但是由于延迟应答机制会稍微等一会返回,这一等正好业务上也要返回内容,此时内核就可以把两个报文合二为一

 

9、面向字节流的"粘包问题":

A应用程序,需要从接收缓冲区中读取收到的数据,由于是面向字节流的,A无法确定从哪到哪是一个完整的应用层数据报

想要解决"粘包问题",只要定义应用层数据协议的时候,明确包和包之间的"边界"(比如约定使用;作为结束标记),就可以了

TCP异常情况:

1、程序崩溃:进程异常退出,操作系统会回收进程的资源,包括释放文件描述符表,这样的释放操作,就相当于调用了对应socket的close,执行close就会触发FIN报文,进一步开始四次挥手~~

2、正常关机:关机的时候,系统会强制结束所有的用户进程;之后的步骤与上述程序崩溃一样

3、主机掉电:非常突然,猝不及防的~~

掉电的是接收方:发送方是不知道对面挂了的,继续发数据(没有ack),之后触发超时重传,重传几次之后仍没有应答,尝试重置链接(也会失败,触发复位报文段RST),最后只能放弃连接

掉电的是发送方:此时接收方就等着,等一阵之后就会发送一个"心跳包",如果对方不返回"心跳包",就说明对方挂了

"心跳包"是周期性触发的,只是一个简单的不携带任何业务数据的包,存在的意义就是确认一下对方是否还在

4、网线断开:情况同主机掉电一样,只不过通信双方的主机都好着呢,这两端各自按照上述两种情况分别进行~~

TCP协议格式:

 

源/目的端口号:表示数据是从哪个进程来,到哪个进程去;

32位序号/32位确认号:32位序号针对请求数据进行的编号,32位确认序号针对应答报文(ACK报文)进行的编号。每一个ACK报文都带有对应的确认序列号,意思是告诉发送者,我已经收到了哪些数据;下一次你从哪里开始发。

4位TCP报头长度:表示该TCP头部有多少个32位bit(有多少个4字节);所以TCP头部最大长度是15 * 4 = 60字节

TCP报头前20个字节是固定的,后面是留给选项的,选项可有可无(它是可变的),选项可以是0个字节,最多是40个字节(什么是选项不做讨论)

6位保留位:现在虽然不用,先占个位置,以后可能会用,也就是留下的可扩展空间

6个特殊标志位(6位):

1、URG:紧急指针是否有效

2、ACK:在数据通信中,接收方发给发送方的一种传输类控制字符,表示发来的数据已确认接收无误。如果接收方成功的接收到数据,那么这一位会被置为1,也就是应答报文(ack报文)这一位置为1。

ACK是系统内核负责的,会在收到请求之后,立即就返回

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

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

5、SYN:请求建立连接;我们把携带SYN标识的称为同步报文段;SYN这一位如果为1说明这是一个同步报文段(尝试和对方建立连接)

SYN是系统内核负责的,会在收到请求之后,立即就返回

6、FIN:通知对方本端要关闭连接了,我们称携带FIN标识的为结束报文段;FIN这一位如果为1说明这是一个结束报文段(通知对方本端要关闭连接了)

FIN是应用程序负责的(代码中主动调用close),何时返回取决于我们的代码

16位窗口大小:存放当前接收方接收缓冲区的剩余大小,这个字段得是在ACK为1的时候(应答报文的时候)才有效,窗口大小是动态的(实时改变)

窗口大小最大不是64kb(也就是16位的最大值),选项中有窗口大小扩展因子来表示更大的值

16位校验和:校验和就是为了检查数据是否出错了(网络传输过程中,受到一些干扰,是容易导致传输的数据出错的),此处的检验和不光包含TCP首部,也包含TCP数据部分。

TCP校验和使用了一个比较常见的CRC算法(循环冗余校验):把TCP报文中的每个字节都进行累加,和也放到一个两个字节的数字中(加的过程中如果溢出了就溢出),最终得到的结果就是校验和

发送方发送数据的时候,就先计算一个校验和,接收方接收的时候,按照同样的规则再算一次校验和,最后看一下两次校验和是不是一样的(这里出现问题的概率还是比较小的)

16位紧急指针:标识哪部分数据是紧急数据;

UDP协议

UDP,即User Datagram Protocol,用户数据报协议

UDP协议的特点:无连接,不可靠传输,面向数据报,全双工

无连接:知道对端的IP和端口号就直接进行传输,不需要建立连接;

不可靠传输:没有任何安全机制,发送端发送数据报以后,如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息;

面向数据报:应用层交给UDP多长的报文,UDP原样发送,既不会拆分,也不会合并;

例如用UDP传输100个字节的数据:如果发送端一次发送100个字节,那么接收端也必须一次接收100个字节;而不能循环接收10次,每次接收10个字节。

全双工:UDP允许通信双方的应用进程在任何时候都能发送数据,UDP的socket既能读,也能写

UDP协议格式:

 

 源/目的端口号:表示数据是从哪个进程来,到哪个进程去;

UDP长度:16位UDP长度,表示整个数据报(UDP首部+UDP数据)的最大容量,一个UDP报文最多就只能有64KB,如果需要使用UDP传输一个比较大的数据,就需要考虑进行拆包

校验和:校验和就是为了检查数据是否出错了(网络传输过程中,受到一些干扰,是容易导致传输的数据出错的)

UDP校验和使用了一个比较常见的CRC算法(循环冗余校验):把UDP报文中的每个字节都进行累加,和也放到一个两个字节的数字中(加的过程中如果溢出了就溢出),最终得到的结果就是校验和

发送方发送数据的时候,就先计算一个校验和,接收方接收的时候,按照同样的规则再算一次校验和,最后看一下两次校验和是不是一样的(这里出现问题的概率还是比较小的)

TCP与UDP区别

 

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信