TCP协议详解

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

TCP协议段格式

在这里插入图片描述

  • 16位源端口/16位目的端口:负责实现应用程序之间的数据传输

  • 32位序号/32位确认序号:用于实现tcp在传输层的包序管理——tcp有序交付数据

  • 4位头部长度:以4个字节为单位;4位保存的最大数字是15;因此tcp报头最大长度是15*4=60个字节

  • 6位保留位

  • 6位标志
    URG——紧急指针标志
    ACK——确认回复标志
    PSH——提示立即接受位
    RST——重置连接位
    SYN——连接建立请求位
    FIN——断开连接请求位

  • 16位窗口大小:滑动窗口机制–>流量控制–>告诉对端所能发送的最大数据量

  • 校验和:二进制反码求和–>校验数据一致性

  • 紧急指针:指明哪些数据是紧急数据

  • 选项数据:三次握手时,协商MSS大小的数据

TCP连接管理

三次握手:所谓的“三次握手”:为了对每次发送的数据量进行跟踪与协商,确保数据段的发送和接收同步,根据所接收到的数据量而确认数据发送、接收完毕后何时撤消联系,并建立虚连接。

在这里插入图片描述

  1. 第一次握手:建立连接时,客户端发送syn包(seq=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
  2. 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(seq=k),即SYN+ACK包,此时服务器进入SYN_RECV状态
  3. 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

四次挥手:TCP使用四次挥手来释放连接(使用一个带有FIN附加标记的报文段)。

1. List item

  1. 第一次挥手:客户端发送一个FIN,用来关闭客户端到服务器的数据传送,表示不再向对方发送数据,发送完毕后,客户端进入FIN_WAIT1状态,等待对方进行恢复。
  2. 第二次挥手: 服务器收到FIN包,向客户端发送一个ACK回复,并进入CLOSE_WAIT状态(等待用户调用close(fd) / shutdown(fd,SHUT_RD) )
    客户端收到ACK回复,进入FIN_WAIT2状态,等待对方发送最后一个FIN包。
  3. 第三次挥手:服务器向客户端发送FIN包,进入LAST_ACK状态,等待回复;
  4. 第四次挥手:客户端收到FIN包,向服务器发送ACK回复,然后进入TIME_WAIT状态,等待2MSL的时间,然后CLOSED。
    服务器收到ACK回复后,CLOSED

FIN包并不仅是关闭套接字的时候会发送;当关闭写端,也会向对方发送FIN包
FIN更多的是告诉对方,我不再给你发送数据了

TCP连接所涉及到的面试问题

1、握手为什么不是 两次/四次 而是三次?
tcp是双向通信,需要双方都要确保对方在线,具有数据收发的能力;假设客户端发送SYN请求后直接推出了;若只是两次就建立连接,服务端发送数据就会丢失;因此服务端收到请求回复后还需要确保客户端也具有数据收发的能力;因此不但要发送ACK还要发送SYN;
只是因为四次没必要二一,因此把ACK和SYN合在一起响应了。

2、挥手为什么是四次而不是三次?
tcp向对方发送FIN不仅仅有close直接不读也不写;也有可能时因为关闭了写端因此发送的FIN;
意味着这一段虽然不再发送数据了,但是还有可能要接收数据;
因此操作系统收到FIN,不能直接断开;因为接收FIN包的这一方有可能还要发送数据过去
因此接收方的ACK和FIN包就不能一起发送,只有接收方不再发送数据了才会发送FIN包

3、FIN包发送方为什么发送最后一个ACK后并没有进入CLOSED状态释放资源,而是进入TIME_WAIT状态等待一段时间?
假设若是没有TIME_WAIT直接进入CLOSED释放资源有可能造成的危险,客户端发送了ACK后,若这个ACK丢包了,服务端将收不到ACK,因此超时后会向客户端重传FIN包。
若客户端又立即使用相同的地址信息启动了客户端,什么都没干突然收到一个FIN,则会对新连接造成影响;
若客户端又立即使用相同的地址信息启动了客户端,向服务端发送SYN,而服务端这时候处于LAST_ACK,收到SYN则会认为状态错误,向客户端发送RST重置连接报文,要求对方重新建立连接。
因此主动关闭方,发送最后一个ACK之后,需要等待一段时间,处理有可能重传的FIN包;
等待的这段时间,时长时两个MSL时间——MSL->报文最大生存周期。
两个MSL指的是重传的FIN以及响应的ACK两个报文的生存时间;目的在于要求本次连接所有数据都消失在网络中,不再对后续新连接造成影响。

4、若三次握手失败了,服务端如何处理的?
1.客户端发送的SYN直接就没有到达服务端——服务端不知道有这个请求,因此没什么处理的。
2.客户端发送了SYN后服务端收到并进行了SYN+ACK响应,但是没有收到ACK; 服务端等待最后一个ACK超时后,则会给客户端发送RST重置连接报文要求对方重新发起连接请求,释放当前新建的这个套接字;而并非重传SYN+ACK。

5、服务器上出现大量的CLOSE_WAIT是什么原因?
CLOSE_WAIT——收到FIN进行回复的状态,等待程序调用close() / shutdown(wr);
表示程序中可能对于大量的套接字连接断开后,没有调用close关闭,释放资源——这是一种代码中的操作

6、服务端出现大量的TIME_WAIT是什么原因?
TIME_WAIT——主动关闭方,发送最后一个ACK之后的状态,意味着服务器上大量主动的关闭了连接——通常出现在爬虫服务器上。
可以开启地址重用 / 设置MSL时间

TCP可靠传输

确认应答机制:接收方对于接收到的每一条数据都要进行确认回复,告诉发送方说数据我收到了。
超时重传机制:发送方发送数据后一段时间内没有收到确认回复,则对数据进行重传。
协议中序号/确认序号字段:进行包序管理,保证数据有序交付。
协议中校验和字段:校验数据一致性;不一致则要求对方进行重传。
在这里插入图片描述
seq:当前数据的起始序号
ack:确认序号—确定这个确认序号之前的数据都已经完整到达
发送端连续发送多条数据,收到的每一个确认回复,都保证其确认序号之前的数据都已经安全到达;
这样的话,就算某个确认回复丢失了,但是又受到了后边数据的确认回复,则会认为这条数据也安全到达了——避免了因为确认回复丢失而导致重传。
超时重传的等待时间:是动态的,随着网络变化的,一开始等待很短的时间就会重传;但是若多条数据都在短时间内无法得到响应,则会调整等待时间。

滑动窗口机制:实现发送方连续发送多条数据,并且进行流量控制——借助协议中的窗口大小字段实现
在三次握手的时候,通信双方会通过选项数据协商MSS(最大数据大小)——一条报文中的数据最大大小。
通过协议中窗口大小字段告诉对方一次最多发送多少数据。

  • 发送方通过维护一个窗口后沿和窗口前沿加上当前发送位置来维护一个发送窗口,表示有多少数据当前可以连续发送。从哪里开始发送,发送到哪里结束,窗口前沿减去窗口后沿就是所能够发送的数据大小
  • 接收方根据自己的接收缓冲区剩余空间大小,使用窗口后沿和窗口前沿,当前接收位置维护一个接收窗口。从哪里开始接收,接收多少,接收的数据放在缓冲区的什么位置。
  • 发送方后沿的移动:取决于是否收到后沿数据的确认回复
  • 发送方前沿的移动:取决于收到的确认中窗口大小;因为前沿减去后沿不能大于窗口大小。
  • 接收方后沿的移动:取决于是否收到后沿的数据
  • 接收方前沿的移动:取决于接收缓冲区中剩余空间大小(取决于用户是否通过recv将数据从缓冲区取出去了)

基于滑动窗口实现数据连续发送又实现一种机制:
快速重传机制:若连续发送多条数据,前边的数据丢失,则会导致接收端不再进行确认回复;因为每一条确认回复,都要保证之前的数据已经到达,第一条数据丢失因此后边的数据收到也不能进行回复。
只能等待发送方超时后重传这些数据,并且超时等待时间比较长;
因此若没有收到第一条数据,而收到了第二条数据,则接收方有理由认为第一条数据丢失了,因此就会每隔一小段时间给发送方发送第一条数据的重传请求,连续发送三次。
发送方连续收到三次同一条数据的重传请求,则对这条数据进行重传。
为什么是三次:因为要防止数据延迟的情况

数据丢失到底重传哪些数据?

  • 停等协议:针对网络状况不好的情况——收到回复才会发送下一条数据
  • 选择重传协议:哪条丢失重传哪条
  • 回退n步协议:从丢失的那条开始后边的数据都重传一下

拥塞窗口:滑动窗口实现了数据的连续大量发送,但是若在通信时,不了解网络状况直接发送大量数据,就有可能大量的丢包重传,因此发送方总是维护一个拥塞窗口进行拥塞控制,实现网络探测,避免因为网络不好造成的大量丢包。

提高传输性能:

  • 延迟应答机制:接收方接收到一条数据,并不立即进行确认回复,因为立即进行回复,会造成窗口变小,造成吞吐率降低。因此延迟一会进行应答,这个延迟期间有可能数据被recv出去,窗口不变 / 变大保证吞吐率。
  • 捎带应答机制:每一条确认回复都是一条数据,至少需要一个tcp报头,为了减少这种纯确认回复报头的数据,因此就会将这次的确认回复和即将要发送的数据合成一个数据进行发送。

面向字节流

字节流传输:发送的数据都会放到发送缓冲区中进行缓冲,字节流传输不管缓冲区数据有多少会自己根据实际情况选择一次发送的数据大小,然后从缓冲区中取出合适大小的数据进行封装发送。

面向字节流传输:传输比较灵活,并不限制上层发送的数据大小以及接收的数据大小
弊端:粘包
粘包就是多条数据粘连在一起被tcp作为一条数据进行发送或交付给上层,可能发生在发送端/接收端。

  • 本质原因:tcp对上层的数据边界并不敏感(不关心上层是什么数据,只管从缓冲区中取出合适大小数据进行发送/交付)
  • 解决方案:tcp在传输层并不对数据进行边界管理,那么就需要应用层程序员自己进行边界管理:
    1、使用特殊字符作为间隔(协议中http协议就是典型)——数据中特殊字符转义
    2、定长数据——资源的浪费
    3、在应用层头部中定义数据长度(典型协议:udp)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值