TCP-连接(转)

    文章大部分描述来自 : https://coolshell.cn/articles/11564.html , 非原创 
    文章大部分描述来自 : https://xiaolincoding.com/network/3_tcp/tcp_interview.html , 非原创 

分层

img

TCP头格式

接下来,我们来看一下TCP头的格式

img

你需要注意这么几点:

  • TCP的包是没有IP地址的,那是IP层上的事。但是有源端口和目标端口。
    一个TCP连接需要四个元组来表示是同一个连接(src_ip, src_port, dst_ip, dst_port)准确说是五元组,还有一个是协议。但因为这里只是说TCP协议,所以,这里我只说四元组。
    注意上图中的四个非常重要的东西:
  • Sequence Number是包的序号,用来解决网络包乱序(reordering)问题。
  • Acknowledgement Number就是ACK——用于确认收到,用来解决不丢包的问题。
    Window又叫Advertised-Window,也就是著名的滑动窗口(Sliding Window),用于解决流控的。
  • TCP Flag ,也就是包的类型,主要是用于操控TCP的状态机的。
    关于其它的东西,可以参看下面的图示

img

TCP 开始连接

看下面的图 , 认真看, 其实整个过程很简单, 就是 client 给出一个 数值 , server 端 + 1 后返回 ,并给出 client 另一个数值 , 假如 client 收到的话,也+1返回 ,这样就完成了3次握手

img

img

img

三次握手的报文

img

Seq Num 和 ISN

握手以后 , 那么数据传输阶段就会依靠三次握手协商出来的 Seq Num 共两个 (客户端一个, 服务端一个 ,对应于上图的 x , y ) .

  • Seq Num(序列号),是 TCP 一个头部字段,标识了 TCP 发送端到 TCP 接收端的数据流的一个字节���因为 TCP 是面向字节流的可靠协议,为了保证消息的顺序性和可靠性,TCP 为每个传输方向上的每个字节都赋予了一个编号,以便于传输成功后确认、丢失后重传以及在接收端保证不会乱序。序列号是一个 32 位的无符号数,因此在到达 4G 之后再循环回到 0
  • ISN(初始序列号 , 就是第一个序列号),在 TCP 建立连接的时候,客户端和服务端都会各自生成一个初始序列号,它是基于时钟生成的一个随机数,来保证每个连接都拥有不同的初始序列号。初始化序列号可被视为一个 32 位的计数器,该计数器的数值每 4 微秒加 1,循环一次需要 4.55 小时

这里可以看到 ISN 并不是每次连接都一样的 ,而是有生成算法的 , 主要的原因 :

  • 当服务端接收到上一次连接发来的包可以鉴别到 .
  • 防止黑客伪装连接

RST 报文

RST 报文即表示重置报文 , 即断开当前连接 , 服务端和客户端都可以发出 . 在下文 : 原因1 : 三次握手才可以阻止历史重复连接的初始化 里收到一个以前的数据包, 那么就会历史连接返回给客户端 .

三次握手的原因

三次握手的原因 :

  • 三次握手才可以阻止历史重复连接的初始化(主要原因)
  • 三次握手才可以同步双方的初始序列号
  • 三次握手才可以避免资源浪费

原因1 : 三次握手才可以阻止历史重复连接的初始化

img

客户端连续发送多次 SYN 建立连接的报文,在网络拥堵等情况下:
一个「旧 SYN 报文」比「最新的 SYN 」 报文早到达了服务端;那么此时服务端就会回一个 SYN + ACK 报文给客户端;客户端收到后可以根据自身的上下文,判断这是一个历史连接(序列号过期或超时),那么客户端就会发送 RST 报文给服务端,表示中止这一次连接。

如果是两次握手连接,就不能判断当前连接是否是历史连接,三次握手则可以在客户端(发送方)准备发送第三次报文时,客户端因有足够的上下文来判断当前连接是否是历史连接:

如果是历史连接(序列号过期或超时),则第三次握手发送的报文是 RST 报文,以此中止历史连接;
如果不是历史连接,则第三次发送的报文是 ACK 报文,通信双方就会成功建立连接;
所以, TCP 使用三次握手建立连接的最主要原因是防止历史连接初始化了连接。

来自 : https://www.cnblogs.com/GuoXinxin/p/11657889.html

假如只进行两次握手,客户端发送连接请求后,会等待服务器端的应答。但是会出现的问题是,假如客户端的SYN迟迟没有到达服务器端,此时客户端超时后,会重新发送一次连接,假如重发的这次服务器端收到了,且应答客户端了,连接建立了。但是建立后,第一个SYN也到达服务端了,这时服务端会认为这是一个新连接,会再给客户端发送一个ACK,这个ACK当然会被客户端丢弃。但是此时服务器端已经为这个连接分配资源了,而且服务器端会一直维持着这个资源,会造成浪费

三次握手,两次握手的问题在于服务器端不知道SYN的有效性,所以如果是三次握手,服务器端会等待客户端的第三次握手,如果第三次握手迟迟不来,服务器端就会释放相关资源。但是有人会问,假如第三次握手没有到达服务器端呢?但是这时客户端认为连接已经建立了。但是其实这种情况下,只要客户端向服务器端写数据,就会收到服务器端的RST应答,这时客户端就能知道出现问题了。

原因2 : 同步双方初始序列号

TCP 协议的通信双方, 都必须维护一个「序列号」, 序列号是可靠传输的一个关键因素,它的作用:

  • 接收方可以去除重复的数据;

  • 接收方可以根据数据包的序列号按序接收;

  • 可以标识发送出去的数据包中, 哪些是已经被对方收到的(通过 ACK 报文中的序列号知道);

半连接队列和全队列

img

img

img

半连接队列 满了怎么办 ?

从上面这样图其实就可以看到一个问题 , 假如黑客攻击 , 一直往服务器发 SYN , 然后服务端将他放到 半连接 队列中 , 并返回一个 ACK + Seq Num , 客户端再断开 ,不再发消息 , 大量这样的请求岂不是会将 半连接 队列堆满 , 然后拖垮服务端 .

确实存在这一类的攻击 , 查了 chatGDP , 给出的答案如下 :

  1. 加强网络安全监控:通过实时监控网络流量和检测异常流量,可以及时发现并阻止Syn攻击。

  2. 开启Syn Cookie功能:Syn Cookie是一种对抗Syn攻击的方法,能够在遭受大量伪造的SYN攻击时自动启用,有效地防止了Syn攻击。

  3. 配置防火墙规则:通过防火墙限制单个IP地址的连接数或拦截伪造源地址的TCP数据包,可以减少Syn攻击的风险。

  4. 调整TCP参数:适当调整服务器端的TCP参数,如增加backlog队列长度、减小SYN Timeout时间等,可在一定程度上缓解Syn攻击。

关于 Syn Cookie功能我们放在下一节介绍 , 这样子章节我觉得会紧凑点 .

全连接队列满了怎么办?

全连接队列满了 ,默认是扔掉的 , 当然我们可以通过设置不同的策略进行处理 , 对应Linux 的参数就是 tcp_abort_on_overflow

# cat /proc/sys/net/ipv4/tcp_abort_on_overflow
0
  • tcp_abort_on_overflow设置为 0,全连接队列满了之后,会丢弃这个第三次握手ACK包,并且开启定时器,重传第二次握手的SYN+ACK,如果重传超过一定限制次数,还会把对应的半连接队列里的连接给删掉。

  • tcp_abort_on_overflow设置为 1,全连接队列满了之后,就直接发RST给客户端,效果上看就是连接断了。

img

img

TCP的状态机

其实,网络上的传输是没有连接的,包括TCP也是一样的。而TCP所谓的“连接”,其实只不过是在通讯的双方维护一个“连接状态”,让它看上去好像有连接一样。所以,TCP的状态变换是非常重要的。

下面是:“TCP协议的状态机”(图片来源) 和 “TCP建链接”、“TCP断链接”、“传数据” 的对照图,我把两个图并排放在一起,这样方便在你对照着看。另外,下面这两个图非常非常的重要,你一定要记牢。(吐个槽:看到这样复杂的状态机,就知道这个协议有多复杂,复杂的东西总是有很多坑爹的事情,所以TCP协议其实也挺坑爹的)

img

这有点像我们做订单系统一样 ,根据单据的状态进行流程的处理一样 .

另外,有几个事情需要注意一下:

  • 关于建连接时SYN超时。试想一下,如果server端接到了clien发的SYN后回了SYN-ACK后client掉线了,server端没有收到client回来的ACK,那么,这个连接处于一个中间状态,即没成功,也没失败。于是,server端如果在一定时间内没有收到的TCP会重发SYN-ACK。在Linux下,默认重试次数为5次,重试的间隔时间从1s开始每次都翻售,5次的重试时间间隔为1s, 2s, 4s, 8s, 16s,总共31s,第5次发出后还要等32s都知道第5次也超时了,所以,总共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 2^6 -1 = 63s,TCP才会把断开这个连接。

  • 关于ISN的初始化。ISN是不能hard code的,不然会出问题的——比如:如果连接建好后始终用1来做ISN,如果client发了30个segment过去,但是网络断了,于是 client重连,又用了1做ISN,但是之前连接的那些包到了,于是就被当成了新连接的包,此时,client的Sequence Number 可能是3,而Server端认为client端的这个号是30了。全乱了。RFC793中说,ISN会和一个假的时钟绑在一起,这个时钟会在每4微秒对ISN做加一操作,直到超过2^32,又从0开始。这样,一个ISN的周期大约是4.55个小时。因为,我们假设我们的TCP Segment在网络上的存活时间不会超过Maximum Segment Lifetime(缩写为MSL – Wikipedia语条),所以,只要MSL的值小于4.55小时,那么,我们就不会重用到ISN。

TCP 的KeepAlive

https://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html

什么是 TCP 的 KeepAlive 以及带来的两个好处

keepAlive 会定时的发送心跳包 , 带来的两个目的 :

  • 检测死亡的链接(Checking for dead peers)
  • 防止在网络不可达的情况下断开连接(Preventing disconnection due to network inactivity)
  • 如果对端程序是正常工作的。当 TCP 保活的探测报文发送给对端, 对端会正常响应,这样 TCP 保活时间会被重置,等待下一个 TCP 保活时间的到来。
  • 如果对端主机宕机(注意不是进程崩溃,进程崩溃后操作系统在回收进程资源的时候,会发送 FIN 报文,而主机宕机则是无法感知的,所以需要 TCP 保活机制来探测对方是不是发生了主机宕机),或对端由于其他原因导致报文不可达。当 TCP 保活的探测报文发送给对端后,石沉大海,没有响应,连续几次,达到保活探测次数后,TCP 会报告该 TCP 连接已经死亡

img

来自 : https://xiaolincoding.com/network/3_tcp/tcp_http_keepalive.html#http-的-keep-alive

关于SYN Flood攻击。一些恶意的人就为此制造了SYN Flood攻击——给服务器发了一个SYN后,就下线了,于是服务器需要默认等63s才会断开连接,这样,攻击者就可以把服务器的syn连接的队列耗尽,让正常的连接请求不能处理。于是,Linux下给了一个叫tcp_syncookies的参数来应对这个事——当SYN队列满了后,TCP会通过源地址端口、目标地址端口和时间戳打造出一个特别的Sequence Number发回去(又叫cookie),如果是攻击者则不会有响应,如果是正常连接,则会把这个 SYN Cookie发回来,然后服务端可以通过cookie建连接(即使你不在SYN队列中)。

请注意,请先千万别用tcp_syncookies来处理正常的大负载的连接的情况。因为,synccookies是妥协版的TCP协议,并不严谨。对于正常的请求,你应该调整三个TCP参数可供你选择

第一个是:tcp_synack_retries 可以用他来减少重试次数;

第二个是:tcp_max_syn_backlog,可以增大SYN连接数;

第三个是:tcp_abort_on_overflow 处理不过来干脆就直接拒绝连接了。

​ 这个过程如下 :

img

​ 当它被设置为1的时候,客户端发来第一次握手SYN时,服务端不会将其放入半连接队列中,而是直接生成一个cookies,这个cookies会跟着第二次握手,发回客户端。客户端在发第三次握手的时候带上这个cookies,服务端验证到它就是当初发出去的那个,就会建立连接并放入到全连接队列中。可以看出整个过程不再需要半连接队列的参与。

那么服务端是如何记住这个 cookies 的呢 ? 不会在服务端保留一份 cookie 吧 , 实际上cookies并不会有一个专门的队列保存,它是通过通信双方的IP地址端口、时间戳、MSS等信息进行实时计算的,保存在TCP报头seq里。当服务端收到客户端发来的第三次握手包时,会通过seq还原出通信双方的IP地址端口、时间戳、MSS,验证通过则建立连接。

既然是计算出来的 , 那么必定在量大的时候会比较吃 CPU .

其他

https://www.cnblogs.com/Benjious/p/15208246.html
https://www.cnblogs.com/Benjious/p/15207148.html

总结

这篇文章大部分内容来自参考资料 , 该篇是进行总结归纳 , 从 tcp 连接开始讲起 ,讲到了关于 keepAlive 还有一些连接中攻击相关的主题 , 以及应对的攻击的一些策略 .

参考资料

posted @   float123  阅读(83)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示