美文网首页
TCP学习总结

TCP学习总结

作者: 风月寒 | 来源:发表于2021-04-19 16:06 被阅读0次

TCP是面向连接的、可靠的、基于字节流的传输层通信协议

面向连接:一对一连接
可靠的:保证一个报文一定能够达到接收端

TCP连接
用于保证可靠性和流量控制维护某些状态的信息,这些信息包括socket、序列号以及窗口大小。
socket:由IP地址和端口号组成
序列号:用来解决乱序问题等
窗口大小:用来做流量控制

tcp头部

1618818345.png

序列号的作用是用来解决网络包乱序的问题。
确任应答号的作用是用来解决不丢包的问题。

控制位:
SYN : 表示请求连接
ACK:确认序号有效
RST:出现异常强制断开连接
FIN:数据发送完成,断开连接,表示不会再发送数据,但仍有接收数据的能力。
Ack序号:只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。
Seq序号:用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。

TCP与UDP的区别

1.连接
TCP是面向连接的传输层协议,每次进行数据传输前需要进行连接
UDP是不需要连接

2.服务对象
TCP是一对一的两点服务。
UDP则可以一对一,一对多,多对多

3.可靠性
TCP是可靠交付数据的,数据可以无差错,不丢失,不重复
UDP尽最大努力交付,不保证可靠交付

4.拥塞控制、流量控制
TCP有拥塞控制和流量控制,保证数据传输的安全性,而UDP则没有。

5.传输方式
TCP是流式传输,没有边界,但保证顺序和可靠
UDP是一个一个包的发送,是有边界的,但可能丢包和乱序

6.分片不同
TCP 的数据大小如果大于 MSS 大小,则会在传输层进行分片,目标主机收到后,也同样在传输
层组装 TCP 数据包,如果中途丢失了一个分片,只需要传输丢失的这个分片。
UDP 的数据大小如果大于 MTU 大小,则会在 IP 层进行分片,目标主机收到后,在 IP 层组装完
数据,接着再传给传输层,但是如果中途丢了一个分片,则就需要重传所有的数据包,这样传输效率非常差,所以通常 UDP 的报文应该小于 MTU。


1618818393.png

MTU:一个网络包的最大长度,以太网中一般为 1500 字节;
MSS:除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度;

三次握手
1618818459.png

1、客户端将标志位SYN 置为1,并随机产生一个序列号seq = J,将改数据包发送给server,然后自己进入SYN_SEND状态。
2、服务端收到数据包后,知道客户端申请建立连接,服务端将标志位SYN和ACK都置为1,ack = J+1,随机产生一个值seq = k,并将改数据包发送给客户端,然后服务端进入SYN_RCVD。
3、客户端收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手

前两次握手是不可以携带数据的,第三次握手是可以携带数据的。

为什么三次握手才可以初始化Socket、序列号和窗口大小并建立 TCP 连接?

1、三次握手才可以阻止重复历史连接的初始化(主要原因)

一般情况下,先发送的数据会先到达主机,但是由于网络拥堵等原因,会导致旧数据先达到目标主机,如果是三次握手,则会在第二次握手的时候,通过seq序列号来判断是否为旧的数据包来进行是否发送RST报文给服务端。如果是两次握手连接,就不能判断当前连接是否是历史连接,三次握手则可以在客户端(发送方)准备。发送第三次报文时,客户端因有足够的上下文来判断当前连接是否是历史连接。

2、三次握手才可以同步双方的初始序列号

3、三次握手才可以避免资源浪费

SYN攻击

假设攻击者短时间伪造不同 IP 地址的 SYN 报文,服务端每接收到一个 SYN报文,就进入 SYN_RCVD 状态,但服务端发送出去的 ACK + SYN 报文,无法得到未知 IP 主机的ACK 应答,久而久之就会占满服务端的 SYN 接收队列(未连接队列),使得服务器不能为正常用户服务。

避免SYN攻击的方式:

1、修改Linux参数,
当网卡接收数据包的速度大于内核处理的速度时,会有一个队列保存这些数据包。控制该队列的
最大值如下参数:net.core.netdev_max_backlog
SYN_RCVD 状态连接的最大个数:net.ipv4.tcp_max_syn_backlog
超出处理能时,对新的 SYN 直接回报 RST,丢弃连接:net.ipv4.tcp_abort_on_overflow

1618818586.png

当服务端接收到客户端的 SYN 报文时,会将其加入到内核的「 SYN 队列」;
接着发送 SYN + ACK 给客户端,等待客户端回应 ACK 报文;
服务端接收到 ACK 报文后,从「 SYN 队列」移除放入到「 Accept 队列」;
应用通过调用 accpet() socket 接口,从「 Accept 队列」取出连接。

1618818627.png

如果应用程序过慢时,就会导致「 Accept 队列」被占满。


1618818671.png

当 「 SYN 队列」满之后,后续服务器收到 SYN 包,不进入「 SYN 队列」;
计算出一个 cookie 值,再以 SYN + ACK 中的「序列号」返回客户端,
服务端接收到客户端的应答报文时,服务器会检查这个 ACK 包的合法性。如果合法,直接放入到
「 Accept 队列」。最后应用通过调用accpet() socket 接口,从「 Accept 队列」取出的连接。

四次挥手
1618818734.png

客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN
报文,之后客户端进入 FIN_WAIT_1 状态。
服务端收到该报文后,就向客户端发送 ACK 应答报文,接着服务端进入 CLOSED_WAIT 状
态。
客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态。
等待服务端处理完数据后,也向客户端发送FIN 报文,之后服务端进入 LAST_ACK状态。
客户端收到服务端的 FIN 报文后,回一个ACK 应答报文,之后进入 TIME_WAIT状态
服务器收到了ACK 应答报文后,就进入了 CLOSED 状态,至此服务端已经完成连接的关闭。
客户端在经过2MSL 一段时间后,自动进入 CLOSED 状态,至此客户端也完成连接的关闭。

主动关闭连接的,才有 TIME_WAIT 状态。

为什么 TIME_WAIT 等待的时间是 2MSL?
MSL 是报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
MSL 与 TTL 的区别: MSL 的单位是时间,而 TTL 是经过路由跳数。所以 MSL 应该要大于等于 TTL
消耗为 0 的时间,以确保报文已被自然消亡。
TIME_WAIT 等待 2 倍的 MSL,比较合理的解释是: 网络中可能存在来自发送方的数据包,当这些发
送方的数据包被接收方处理后又会向对方发送响应,所以一来一回需要等待 2 倍的时间。等待足够的时间以确保最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭。

TIME_WAIT过短会怎样?
如果TIME_WAIT过短,则会主动关闭方直接进入CLOSED状态,而被动关闭的一方则一直处于LAST_ACK状态,此时当客户端发起建立连接的SYN请求报文后,服务端回发送RST报文给客户端,连接建立的过程就会被终止。

TIME_WAIT 过多有什么危害?
第一是内存资源占用;
第二是对端口资源的占用,一个 TCP 连接至少消耗一个本地端口;

Socket流程
1618818816.png

服务端和客户端初始化 socket ,得到文件描述符;
服务端调用bind ,将绑定在 IP 地址和端口;
服务端调用listen ,进行监听;
服务端调用accept ,等待客户端连接;
客户端调用connect ,向服务器端的地址和端口发起连接请求;
服务端 accept 返回用于传输的 socket 的文件描述符;
客户端调用 write 写入数据;服务端调用 read 读取数据;
客户端断开连接时,会调用 close ,那么服务端 read 读取数据的时候,就会读取到了
EOF ,待处理完数据后,服务端调用 close ,表示连接关闭。

服务端调用 accept 时,连接成功了会返回一个已完成连接的 socket,后续用来传输数据。
所以,监听的 socket 和真正用来传送数据的 socket,是「两个」 socket,一个叫作监听 socket,一个叫作已完成连接 socket。

Linux内核中会维护两个队列:
未完成连接队列(SYN 队列):接收到一个 SYN 建立连接请求,处于 SYN_RCVD 状态;
已完成连接队列(Accpet 队列):已完成 TCP 三次握手过程,处于 ESTABLISHED 状态;

1618818863.png

客户端 connect 成功返回是在第二次握手,服务端 accept 成功返回是在三次握手成功之后。

1618818906.png

超时重传
就是在发送数据时,设定一个定时器,当超过指定的时间后,没有收到对方的 ACK 确认应答报文,就会重发该数据,也就是我们常说的超时重传。
在下面两种情况会发生重传:
数据包丢失
确认应答丢失

超时时间应该设置为多少呢?
RTT:数据从一端传送到另一端所需要的时间。
RTO:超时重传时间
当RTO太大,重发就慢,效率低,性能差。
当RTO太小,会增加网络拥塞,导致更多的超时。
所以RTO的时间设置是略大于RTT。

如果超时重发的数据,再次超时的时候,又需要重传的时候,TCP 的策略是超时间隔加倍。
也就是每当遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前值的两倍。两次超时,就说明网络环境差,不宜频繁反复发送。

这种方式超时周期可能相对较长,所以采用一种快速重传机制来解决超时重发的时间等待。

快速重传,它不以时间为驱动,而是以数据驱动重传。

1618819096.png

快速重传机制只解决了一个问题,就是超时时间的问题,但是它依然面临着另外一个问题。就是重传的时候,是重传之前的一个,还是重传所有的问题。采用SACK方式。

SACK
这种方式需要在 TCP 头部「选项」字段里加一个 SACK 的东西,它可以将缓存的地图发送给发送
方,这样发送方就可以知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据。


1618819132.png

SACK 来告诉「发送方」有哪些数据被重复接收了。

滑动窗口
TCP 是每发送一个数据,都要进行一次确认应答。当上一个数据包收到了应答了, 再发送
下一个。这样的传输方式有一个缺点:数据包的往返时间越长,通信的效率就越低。

窗口大小就是指无需等待确认应答,而可以继续发送数据的最大值。

TCP 头里有一个字段叫 Window ,也就是窗口大小。
这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的
处理能力来发送数据,而不会导致接收端处理不过来。
所以,通常窗口的大小是由接收方的窗口大小来决定的。
发送方发送的数据大小不能超过接收方的窗口大小,否则接收方就无法正常接收到数据。

发送方窗口

1618819174.png

SND.WND:表示窗口的大小。
SND.UNA:表示已发送但未收到ACK确认的数据
SND.NXT:表示未发送但在接收方范围之内的数据。

接收方窗口


1618819210.png

RCV.WND :表示接收窗口的大小,它会通告给发送方。
RCV.NXT :是一个指针,它指向期望从发送方发送来的下一个数据字节的序列号,也就是 #3 的
第一个字节。

流量控制是避免「发送方」的数据填满「接收方」的缓存,但是并不知道网络的中发生了什么。
在网络出现拥堵时,如果继续发送大量数据包,可能会导致数据包时延、丢失等,这时 TCP 就会重传
数据,但是一重传就会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,这个情况就会进
入恶性循环被不断地放大....

拥塞控制
拥塞控制,控制的目的就是避免「发送方」的数据填满整个网络。

拥塞窗口,根据网络的拥塞程度动态的发生变化。
与发送窗口和接收窗口的关系:发送窗口大小 = min(拥塞窗口大小,接收窗口大小)

拥塞控制算法:
慢启动,拥塞避免,拥塞发生,快速恢复


1618819248.png

会设置一个慢启动阈值,当小于这个阈值的时候,则采用慢启动算法,当大于这个阈值的时候,采用拥塞避免算法。ssthresh 的大小是 65535 字节

慢启动算法:
连接建立完成后,一开始初始化 cwnd = 1 ,表示可以传一个 MSS 大小的数据。
当收到一个 ACK 确认应答后,cwnd 增加 1,于是一次能够发送 2 个
当收到 2 个的 ACK 确认应答后, cwnd 增加 2,于是就可以比之前多发2 个,所以这一次能够发
送 4 个
当这 4 个的 ACK 确认到来的时候,每个确认 cwnd 增加 1, 4 个确认 cwnd 增加 4,于是就可以
比之前多发 4 个,所以这一次能够发送 8 个。

拥塞避免算法:

每当收到一个ACK,cwnd增加1/cwnd。

前面两种是拥塞避免算法。往发送重传机制的时候,就会进入拥塞发生算法.。
重传有两种方式:超时重传和快速重传。
发生超时重传的拥塞发生算法:

1618819291.png

这种方式就重新开始慢启动,慢启动是会突然减少数据流的。这真是一旦「超时重传」,马上回到解放
前。但是这种方式太激进了,反应也很强烈,会造成网络卡顿。

发生快速重传的拥塞发生算法

cwnd = cwnd/2 ,也就是设置为原来的一半;
ssthresh = cwnd ;
进入快速恢复算法

1618819329.png

拥塞窗口 cwnd = ssthresh + 3 ( 3 的意思是确认有 3 个数据包被收到了);
重传丢失的数据包;
如果再收到重复的 ACK,那么 cwnd 增加 1;
如果收到新数据的 ACK 后,把 cwnd 设置为第一步中的 ssthresh 的值,原因是该 ACK 确认了新
的数据,说明从 duplicated ACK 时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的
状态了,也即再次进入拥塞避免状态;

相关文章

  • TCP学习总结

    TCP是面向连接的、可靠的、基于字节流的传输层通信协议 面向连接:一对一连接可靠的:保证一个报文一定能够达到接收端...

  • TCP协议学习总结(下)

    在前两边TCP学习总结中,也大概地学习了TCP的整个流程,但许多细节中的细节并没有详细学习,例如超时重传问题,每次...

  • Socket通信

    最开始学习过Socket编程,半年没看有所遗忘,在这里简单总结一下。 一. 总览 TCP TCP 协议提供面向连接...

  • 暑假周报(二)

    本周学习内容 网络学习,看了《图解TCP/IP》第一章后面一部分,并做了总结,博客总结 Unity学习方面游戏的音...

  • 关于TCP和Https的简单理解

    学习总结,仅供自己参考,如有不对欢迎指正 传输控制协议 一、关于TCP 1.TCP分层原因: 1.因为网络的不稳定...

  • TCP协议学习总结(上)

    在计算机领域,数据的本质无非0和1,创造0和1的固然伟大,但真正百花齐放的还是基于0和1之上的各种层次之间的组合(...

  • TCP协议学习总结(中)

    很多人都说TCP协议是一个十分复杂的协议,在学习当中,我对协议每一个问题都分解学习后,每一个分解我都能体会和理解它...

  • TCP和UDP的区别

    TCP和UDP的区别: TCP协议和UDP协议特性区别总结: TCP协议可靠;UDP协议不可靠 TCP协议是面向连...

  • 面试-《图解HTTP》一

    最近在看《图解HTTP》,将TCP/UDP相关内容做一个总结,也算是系统的学习一下这个知识点。 1.TCP/IP协...

  • 理解TCP和UDP

    一、TCP端口 二、TCP报文结构 三、TCP连接的建立和释放 TCP的整个交互过程可总结为:先建立连接、然后传输...

网友评论

      本文标题:TCP学习总结

      本文链接:https://www.haomeiwen.com/subject/npwilltx.html