文章目录
前言
前面关于对UDP协议的讲解,不知道大家对UDP协议的认识是否多了一步!
而今天的主角——TCP,比UDP要完美许多!!!
当然内容以及面试的出现频率也高了不少,好啦,话不多说开干~~)
提示:以下是本篇文章正文内容,下面案例可供参考
1.TCP协议
TCP协议,是传输层协议之一,又名传输控制协议;
那么你知道TCP协议是怎么实现的吗??
2、协议实现
2.1、TCP协议格式模型
2.2、字段分析
- 16位的源端,对端端口:标记进行通信两端进程的端口;
- 32位的序号:告诉接收方,这条数据在整体数据中的排序方式,
使数据有序交付!!!
在tcp传输中,数据长度受限,因而数据太大需按制定大小数据分组发送,进而涉及数据的排序问题;
- 32位的确认序号: 想发送方,进行回复确认,确认序号之前的数据收到;
注:
1.确认序号不是都从1或0开始,而是随机的;
2.数据超过32位的4G大小,其会重新商议一个起始序号,进行发送;
-
4位的头部长度: 虽然是4位,但是每位是以4字节为单位描述tcp报头头部,
因而tcp报头最长60字节,最小20字节(固定已有数据字段)
- 对数据的解析:接受方会(a)首先取出20字节的固定长度数据;(b)根据头长,确定选项数据,剩下的部分则为应用层数据;
接受方接受到的tcp数据,置于缓冲区的部分,是不含头部!!!
也就是多个数据存放在接受缓存区中,是不区分边界的,故TCP数据存在粘包问题
;
-
6位标志位: 标志位实则标记了连接请求的各个状态;
FIN : 置为1,表示
请求与对方关闭连接
;
SYN: 置为1,表示当前强求是连接建立请求
;
RST:置为1,重置连接请求
,通常有服务端向客户端发起,连接状态一般(有问题,非法);
PSH:表示要求对方尽快将数据取出
;
ACK :确认应答
,表示对方请求已接收;(确认序号)
URG:紧急指针
有效位;
- 16位窗口大小:用于实现滑动窗口机制(避免丢包重传),实现流量控制;
- 主要解决的问题是,当发送发一直发送数据,若接受缓冲区数据满了,则会存在数据的丢失以及重传,降低了效率;
- 而窗口大小这一字段,则是在每一次回复中,回复当前剩余缓冲区空间大小,
使得每次发送的数据的就可以控制在小于等于接受缓冲区剩余空间大小以内
;
- 16位校验和:校验接受数据是否与发送时的数据是否保持一致——二进制求和算法;
(上文曾提过该算法UDP协议讲解);
- 16位紧急指针: 指向紧急带外优先数据的结束位置;
其对应标志位中的URG标志位,主要是为了优先处理某些较为紧急的数据;
且该紧急数据被置于报文中,选项数据与应用层数据之间;
3、协议特性
TCP协议三大特性: 面向连接,可靠传输,面向字节流;
3.1、面向连接
面向连接,通信前,要先建立连接,确保都具有数据收发
的能力;
那么TCP是如何建立连接,以及断开的连接的吗??
3.1.1、建立连接(三次握手~)
三次握手意在确保双方都是具有数据的收发能力!!!
三次握手的图文分析
3.1.2、三次握手的相关面试题解析~~
问题一
:握手为什么是三次?-
解析 :
两次不安全,四次没必要!!!
-
两次不安全:
- 1.通信双方都需要确认对方具有收发数据能力,不能单方面的确认,不然容易受到黑客的攻击(黑客伪造客户端IP,向服务端发送了大量的SYN请求,占据大量资源~~)
- 2. 对于客户端回复SYN延迟到达,服务端会要求。进行重传,此时两次的SYN会发送冲突,而此情况,由于是三次握手,服务在接受SYN请求后,会SYN_RCVD状态,自动忽略重传的SYN请求! -
四次没没必要:
- . 四次主要针对的就是服务端对客户端第一次SYN请求回复的ACK与SYN, 是否分开发送,实则其只是TCP报头中的标志位,可一次置为1,进行回复,反之,若分开发送,多的一次TCP数据的发送,实则导致了多发20个字节的报头数据,存在无效资源浪费
-
问题二:
三次握手失败了,双端如何进行处理的?- 若客户端第一次发送的SYN请求丢了,客户端请求重传;
- 若第二次握手失败,即可能服务端回复的ACK+SYN丢了,客户端(
以为自己的SYN丢了
)会进行重传,服务端等待ACK回复超时(以为对方是恶意访问
),给客户端发送一个RST请求,释放套接字资源; - 若第三次握手失败,即服务端未收到客户回复的最后一次ACK,同上,服务器等待超时,回复RST后,释放资源;
3.1.3、断开连接(四次挥手~~)
通信接受后,会有一个断开连接的过程,避免出现意外~~
四次挥手图文分析
3.1.4、四次挥手相关面试题解析~~
面试题一
:挥手为什么是四次?- FIN请求的只能表示主动关闭方,不在发送数据,不代表不再接受数据,因此,被动关闭方接受FIN请求并进行ACK确认后 ,仍有可能向发送FIN请求的一方,发送数据,等待上层不再发送数据了,也要关闭套接字了,才发送FIN请求~~
面试题二
:一台主机上出现了大量的CLOSE_WAIT状态,这是为什么?-
- CLOSE_WAIT状态,是被动关闭方,确认收到对方发来的FIN包且进行ACK确认后进入的状态~
-
- 一直处于CLOSE_WAIT状态,而没有进入下一状态,是因为上层没进行关闭套接字操作,即进而无法向对方发送FIN请求;
- 以上,其原因在于代码中没有针对断开连接套接字进行关闭操作!
-
面试题三
:TIME_WAIT状态有什么用,为什么不直接关闭套接字释放资源?- TIME_WAIT状态,是主动关闭方进行最后一次ACK回复后进入的状态;
- 若没有TIME_WAIT状态,主动关闭方直接释放套接字资源,有可能出现新启动的套接字复用原IP和端口;
- 而上一次连接可能最后一次ACK请求会丢失,一旦丢失,被动关闭方,会重传FIN包,而新连接由于使用了之前相同的地址信息,进而导致重传FIN包对新的连接造成影响~~~
因此不能直接释放资源,*需要等待两个MSL时间*,针对有可能存在的FIN重传,进行处理,保证上一次通信的所有数据消失在网络中!!
(MSL)
面试题四
: 一台主机上出现了大量的TIME_WAIT状态是什么原因,如何处理?- TIME_WAIT状态,是主动关闭方进行最后一次ACK回复后进入的状态,等待一段时间是为了处理可能发送的ACK丢失重传FIN包的现象;
- 因此一台主机出现大量TIME_WAIT连接,是因为主机上大量的主动关闭了连接,占据了大量端口;(常见于爬虫服务器)
- 解决一方面,配置TIME_WAIT的时间,可将设置的更短!
- 另一方面,有一个套接字选项,叫做地址重用,针对异常的套接字,(例如当前一个连接使用一个地址一个端口,新连接仍可使用该地址和端口),使用setsockopt()接口~
3.1.5、TCP连接管理中保活机制
- 连接断开,有一个信息:recv函数返回0、send出发异常(SIGPIPE);
- TCP通信中,如果客户端,服务端通信频率不高,中间突然网断了~
- 在通信过程中,
客户端与服务端若长时间无通信(默认7200s)会自动的想客户端,发送一个保活探测心跳包,要求对方进行响应(默认每隔75s),若多此无响应(默认9次),则认为连接断开;
- 这些默认数据都是可以配置的,甚至可通过套接字选项设置~~~
(在连接断开后,程序并不会立即退出,所以通常网络程序会在初始阶段都会初始化SIGPIPE信号,避免此情况的发生!)
4、可靠传输
通过很多特殊机制实现~~
面向连接: 确保双方都具有收发数据的能力;
丢包检测机制-确认应答机制: 接受方要针对收到的每条数据进行确认回复;
丢包重传机制-超时重传机制: 等待确认回复超时则重传;
序号字段: 进行包序管理,有序交付;
校验和字段: 检验数据一致性,不一致则丢弃,要求重传;
而没有必要性能损失处理机制,你知道有哪些吗~~~
4.1、避免丢包重传
滑动窗口机制
滑动窗口机制实则就是为实现流量控制~~
1、作用内容
其通过协议中的窗口大小字段,接受方告诉发送方最大的发送数据量,避免因为发送数据过多,而其接收方缓冲区承载不够,导致的溢出丢包现象;(窗口大小字段中的值,不能大于接收缓冲区中剩余空间大小
);
2、实现
增添两个概念;
MSS: 最大的数据段大小,表示在TCP传输中,应用层数据的最大大小,在三次握手阶段,tcp通信双方会进行协商(协商,MSS的实际大小为双方MSS较小的值);
MTU: 最大的传输单元大小,是链路层限制的最大数据帧大小~
而TCP传输中,在使用send发送数据时,是把数据放到了发送缓冲区中,系统选择合适的时候,从发送缓冲区中取出合适长度大小(不大于MSS)的数据,进行封装报头进行发送~~
-
发送方
发送方维护了一个发送窗口(大小不大于对方回复的窗口大小字段值),窗口内的数据是可发送数据;- 窗口后沿:数据发送的起始序号,收到确认回复后向后移动;
- 窗口前沿:数据发送的结束序号,随对方发送窗口大小而定;
-
接收方
接受方维护了一个接收窗口,(大小不大于接收缓冲区剩余空间大小)- 窗口后沿:要接收数据的起始序号,窗口区域的起始位置;
(收到对应起始序号数据后,后沿后移) - 窗口前沿:接收数据的结束序号,窗口区域的结束位置;
(后沿移动:1.取出缓冲区数据;2.设置套接字选项扩大缓冲区大小)
前沿如何向前移动呢?
可人为缩小缓存区大小~~~
- 窗口后沿:要接收数据的起始序号,窗口区域的起始位置;
3、滑动窗口集机制中的三种特殊协议
1.停等协议: 发送一条消息,必须等到对方确认回复后才发下一条;
2.回退n步协议: 发送一条数据,若丢包,则将丢包的数据及其往后的数据都会进行重传;
3.选择重传协议: 管线化传输,哪条丢了就只重传哪条~(tcp协议1.1版本新增的管线化
)
拥塞机制
拥塞机制,避免网络拥塞而导致丢包,实际上是一种网络探测式的传输~~
1、拥塞机制的内容
发送方会维护一个拥塞窗口,同时会选择拥塞窗口和滑动窗口较小的一个作为传输大小,起始序号为1,阈值初始为16;
拥塞窗口以指数级进行增长:1,2,4,8,16…
在增长过程中,一旦出现超时丢包,此时有理由判断当前网络拥塞
- 阈值变为当前窗口的一半大小,窗口大小从1重置;
- 当拥塞窗口达到阈值后,进行线性化增长,每次增长1;
后面会追加一个快速回复,一旦出现快速重传的丢包现象,认为网络不一定拥塞(毕竟接收到了后面数据)
- 拥塞窗口和阈值变为当前窗口的一半;
- 之后进行线性的增长;
4.2、其他提升性能的方式
1.延迟发送机制: 数据先放在缓冲区中,延迟一段时间在发送(减少IO次数)
(不适用于适时性较高的场景,如SSH协议,但可通过套接字选项修改~)
2.延迟应答机制: 收到数据后,延迟一段时间在确认回复(维持吞吐量)
(数据放置接收缓冲区中,延迟应答,可使得数据被取出后,向对方应答的窗口保持一个较大值~)
3.快速重传协议: 尽量减少超时等待的时间
- 快速重传协议
首先,回顾一下tcp头部字段中的确认序号;
确认序号的回复,即告诉对方在此确认序号的数据都已收到~~;因而在数据传输中,如果某条确认应答丢了,而后续数据的确认应答收到,则也可说明前面的数据收到了,此也避免了确认应答丢失而重传的现象;
但是,在传输过程中,某个数据包丢了,接受窗口未收到该数据的起始序号,而收到了后续数据的起始序号,则我们有理由认为,该条数据已丢失!此时就会启动快速重传机制!
在每收到后面一条数据,就会确认回复一下前面没有收到那条数据的起始序号,即让对方对该序号数据进行重传,但是发送方,收到前面数据的确认序号应答,也不会立即对该条数据进行重传,而是连续收到三次后(避免数据延迟到达而重传),在进行操作!!!
5.面向字节流
5.1、内容及特性
- 面向字节流: 提供字节流式传输(一种有序,安全且可靠,基于连接的字节传输)
- 字节流传输,发送或接受都是以字节为单位;
- 大致内容:
发送方将要发送的数据放置于发送缓冲区中,系统截取合适大小的数据进行传输~
接受方接收的数据,放在接收缓冲区中,上层recv要多少给多少~
字节流传输其本身较为灵活,没有发送或接收长度的限制~;
但是,TCP传输,较UDP传输有一个特点,其在将数据放置缓冲区,其中是不含有TCP的报文头部的,就是放置缓冲区中的是“赤裸裸”的数据咯~~;
因而,TCP的字节流传输,也存在一个缺陷——粘包问题!!!
粘包问题: 系统将多条数据当作一条数据进行处理了!
而TCP对数据边界不做任何特殊处理,使得数据之间无边界管理
,才导致了粘包问题;
- 解决:
1.数据之间以特殊字符作为间隔;
- 优点:思想操作简单;
- 缺点:数据中不能有特殊字符,需要进行类似URI编码和URI解码操作;
2.数据定长;
- 优点:思想操作简单;
- 缺点:对定长大小,数据小了,浪费性能,数据大了不够用;
3.TLV数据格式:含有type,length,value字段
与UDP数据的拆分原理类似~~
- 发送每条数据都有一个固定头部:type,length;
- 思想就是先获取固定头部,然后根据头部中的length确定数据长度;
总结
以上,便是博主关于TCP协议的所有总结~~
希望能给兄弟萌,带来帮助~未来必拿大offer!!!