TCP协议
一、简述
二、TCP报文段首部格式
- 源端口号、目的端口号与UDP的一样。
- 序号seq,用来表示当前字节流的第一个字节的位置。因为字节流可能会被切割成多份,所以需要通过序号标识现在到哪了。
- 确认号ack,应该是接收方返回给发送方时发送的内容。表示我后面想接收到从哪个序号开始的字节流,而确认号之前的字节流已经被我接收到了。
- 数据偏移(首部长度):也就是用来表示首部的长度的,单位是4B。首部长度最多可以是60B
- 标志位,这些标志位非常重要。
- 紧急位URG:URG=1,表示当前报文段包含紧急数据,需要赶紧发。不需要在缓存队列中排队了,可以直接跳到最前面发送。结合紧急指针一起用。
- 确认号ACK:在连接建立之后,ACK=1,以后发送的报文都要将ACK置为1。
- 推送位PSH:这个标志位主要应用于接收端。PSH=1的时候,表示接收缓冲区的数据不需要再等满了再上传了,直接上传到应用层。
- 复位RST:RST=1的时候,表示连接出错,要释放连接重新连接。
- 同步位SYN:在握手连接的时候,客户端和服务端都将SYN置为1,表示当前处于请求连接状态。
- 终止位:FIN=1,表示此报文段数据已经方法,可以释放连接了。
- 窗口:用于接收方给发送方,用于表明当前接收缓存区还有多少空间可以接收数据。
- 检验和:与UDP一样,加一个伪首部然后计算检验和。其中,第四个字段,用于标识协议的字段,设置为6。
- 紧急指针:与紧急位URG一起使用。表示当前报文段到哪个位置为止是紧急的字段。
- 选项:可以额外添加一些字段。
三、TCP连接管理
1. 连接建立(三次握手)
- 首先,先说明,连接状态中,最重要的一个标志位是SYN,表示目前处于请求连接状态。而SYN和ACK标志位必须是成对出现的,请求方发送一个SYN,必须收到对方的ACK作为确认。
- 其次就是序号seq和确认号ack,这是成对出现的,表示报文段的起始序号以及确认收到序号。
1.1 第一次握手
- 第一次握手是客户端向服务端发送请求。
- 首先将SYN置为1,表示目前是在请求连接过程。
- 并且随机生成一个seq,表示当前报文段的起始序号。(随机生成的原因是,防止两次请求之间产生冲突)
1.2 第二次握手
- 当服务端接收到客户端发过来的连接请求之后。
- 首先,也会将SYN置为1,表示目前处于回复请求连接的过程,对于服务端来说也是一个请求连接的过程。
- 并且将ACK置为1,表示目前确认了客户端的SYN请求。
- 针对接收到的序号seq,需要回复一个ack确认号,表示已经收到了,并且表明自己下一个想接收到的序号是seq+1
- 对于自己当前发送的报文段,也需要生成一个随机的序号seq
- 服务端会分配缓存区和变量
1.3 第三次握手
- 当客户端接收到服务端的回复之后。
- 面对服务端的SYN请求,必须回复一个ACK=1,表示客户端也同意同步。
- 针对服务端的seq,发送一个确认号ack=seq+1
- 针对服务端的ack,发送一个报文段起始序号ack+1
- 数据区可以携带数据过去了
- 客户端也会分配缓存区和变量
1.4 三次握手的目的
- 因为SYN请求和ACK确认必须是双方确认的过程。当客户端给服务端发送SYN的时候,需要得到服务端的ACK确认;当服务端发送SYN的时候,也需要服务端的ACK确认。
- 如果使用两次握手,就至多完成一次确认,没办法完成双方确认。有可能,客户端发生第一次握手的时候因为网络原因,过了超长时间才到达服务端;客户端以为已经超时了,放弃了此次连接;但是服务端不知道客户端已经放弃了此次连接,直接建立起了连接,就会造成资源的浪费。
- 如果使用四次握手,服务端发送SYN和ACK分开来发。实际上是没有必要的,因此,将它们合并成一条报文段即可。因此使用三次连接
1.5 SYN洪泛攻击
2. 连接释放
- 提前说明,连接释放最重要的是结束标志FIN以及确认标志ACK。
2.1 第一次挥手
- 第一次挥手,由客户端发起请求。
- 客户端将FIN置为1,表示请求释放释放连接。
- 并且将序号设置为一个随机数u
2.2 第二次挥手
- 第二次挥手,服务器给客户端进行回复。
- 将ACK置为1,并对第一次挥手的序号进行确认ack=u+1
- 并将序号设置为一个随机数v
- 此次报文没有回复FIN的原因是,有可能服务端这边还没有发送完手边的数据,因此还需要继续发,不能立即请求结束。
2.3 第三次挥手
- 第三次挥手,依旧是服务端给客户端进行发送。
- 这次是服务端主动发起断开连接请求,将FIN=1
- 并且ACK置为1,并且ack=u+1,表示这是对上一次客户端断开请求的补充。
- 此次会再次随机生成一个序号w
2.4 第四次挥手
- 第四次挥手,是客户端给服务端确认。
- 客户端对服务端的FIN请求表示确认,ACK=1。并且ack=w+1,表示这是对于第三次挥手的确认。
- 序号设置为u+1。
- 就此完成了关闭操作。
2.5 四次挥手的目的
- 其实和三次握手的原理基本类似,就是因为断开连接也是一种双方同意确认的过程。
- 但是不同的是,客户端是确认好没有消息要发了,才请求的断开;
- 但服务器并不是,服务器收到断开请求的时候,有可能还有数据需要发送。因此,在服务端这边,将确认报文和断开请求报文分开。在收到客户端请求断开的时候,首先发送一个ACK确认,告诉它,我收到了,不要再发了!然后服务端继续完成手头上的工作,完成之后,再请求断开。
四、TCP可靠传输
- 可靠传输,就是保证接收方进程从缓存区读出的字节流与发送方发出的字节流是完全一样的。
1. 校验
- 与UDP使用校验和过程一样
2. 序号
- 序号就是用来确定当前报文段的数据部分,是在字节流中的位置。一个序号占一个字节。
3. 确认
- 和首部字段的ack字段密切相关。就是用来让发送方确认当前接收到哪个部分的内容,后面想接收从哪开始的字节流。
- 值得一提的是,tcp采用的是累积确认,如果中间缺了一部分,则ack一直都是缺了那部分的首字节的序号。直到缺省的字节流到达。(比如说下面,如果4开头的字节流没有到达,即使7开头的字节流已经到达,ack也只会发4)
4. 重传
- 当发送方在超过规定时间内没有接收到确认信息,发送方就会重传。
- 而这个重传的时间,在TCP当中,采用一种自适应算法,简单来说就是统计加权平均下的往返时间,从而确定重传时间。
- TCP还采用了一种冗余ACK的机制。当接收方收到比期望序号ACK大的报文段时,回复的期望序号ACK依旧写没到达的那个报文段的序号。而发送方如果收到了3个冗余ACK,就会判断此报文段已经丢失,然后就快速重传。
五、TCP流量控制
- 接收方让发送方慢点,要让接收方来得及接收。
- TCP采用滑动窗口的机制实现流量控制。
- 待发送的缓冲区实际上是一个队列/数组,窗口由两个指针组成,起始和结束。而这个窗口的大小由接收方返回的窗口rwnd和拥塞窗口cwnd的最小值确定。简单来说,就是通过被控制的窗口大小,控制当前可发内容的大小。
- 接收方可以接收多少数据,就设置窗口有多大,发送方就会将窗口内的内容发送给接收方。当接收方还没确认可以再接收之前,发送方就在这等着;当接收方确认并告诉发送方可以发送的窗口大小之后,发送方又可以发送数据了。
- 以下为实际案例,接收方调整了三次滑动窗口大小。
- 值得一提的是,第三次调整滑动窗口大小为0,表示发送方不能再发送消息了,发送方就会在那等着。如果接收方再发送一次设置滑动窗口,发送方就可以继续发。发送方在暂停的时候还会有一个计时器,超过时间没收到调整窗口大小的时间后,它就会发一个探测报文段。
六、TCP拥塞控制
- 拥塞控制,是由于网络资源有限,在网络上有大量的数据注入,而网络的吞吐量不足以承载这么大的负荷而造成的。
- 网络拥塞是一个全局性的事情,并不是一台主机就造成的。
- 而拥塞控制和流量控制一样,都是通过控制发送窗口的大小实现。发送窗口的大小就等于
Min{接受窗口rwnd,拥塞窗口cwnd}
- 拥塞窗口是发送方自己察觉自己修改的。
1. 慢开始&拥塞避免
- 过程如下:一开始拥塞窗口指数增长,增长到上一次造成拥塞的窗口大小的1/2时,开始加法递增;当递增到网络拥塞之后,拥塞窗口大小立即下降到1,然后重新开始。
- 慢开始就是从1一开始,指数增长的过程。
- 拥塞避免就是递增的那一段过程。
2. 快重传&快恢复
- 过程如下:一开始还是以慢开始、拥塞避免开始。但达到网络拥塞之后,拥塞窗口大小并不会直接下降到1,而是会对阻塞窗口减半,然后继续加法递增。
- 其中,对拥塞窗口减半继续执行的操作,就被称为快恢复。
- 而判断网络拥塞的依据是,接收到3次重复确认的ACK。
转载自:https://juejin.cn/post/6962452613593825311