加入收藏 | 设为首页 | 会员中心 | 我要投稿 衡阳站长网 (https://www.0734zz.cn/)- 数据集成、设备管理、备份、数据加密、智能搜索!
当前位置: 首页 > 运营中心 > 网站设计 > 教程 > 正文

聊点TCP干货

发布时间:2019-05-29 08:43:47 所属栏目:教程 来源:美码师
导读:我们在平时的开发中,或多或少都会涉猎到网络传输这块。 这篇文章,主要是整理一下 TCP 的一些知识要点,作为一名开发者来说,尽管有那么多的基础设施(框架、组件)帮我们屏蔽了这些细节。但我仍然认为了解它的一些基本原理必有些裨益,尤其是当你在分布式

在建立TCP连接时,需要经过三次交互,也成为三次握手(HandShake)。

  • 客户端发起连接请求,发送 SYN包(SYN=i)到服务器,并进入到SYN-SEND状态,等待服务器确认
  • 服务器收到SYN包后,必须确认客户的 SYN(ack=i+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器进入SYN-RECV状态
  • 客户端收到服务器的SYN+ACK包,向服务器发送确认报ACK(ack=k+1),此后客户端和服务器进入ESTABLISHED状态,双方可以开始传送数据。

在谈论三次握手的时候,有几个问题是需要关注的:

问题1. 为什么是三次握手

这个问题在技术面试时屡试不爽,原话是能不能两次,或者是四次握手呢?

答案就是,TCP 是可靠的传输,在建立连接时就应该经过两端的确认过程,如上面的流程,

只有在三次握手的情况下,客户端和服务端都经过了一次真正(SYN+ACK)的确认过程。这样的连接便认为是可信的。

此外,如果仅仅只是两次握手,一旦网络不稳定造成 SYN 包重传则会直接导致重复建立连接,浪费资源。

问题2. 什么是syn flood攻击

syn flood 是一种经典的 ddos攻击手段,这里面用到了TCP 三次握手存在的漏洞。

在上面的图中,可以看到当服务端接收到 SYN 后进入 SYN-RECV 状态,此时的连接称为半连接,同时会被服务端写入一个 半连接队列。

想象一下,如果攻击者在短时间内不断的向服务端发送大量的 SYN 包而不响应,那么服务器的 半连接队列很快会被写满,从而导致无法工作。

实现 syn flood 的手段,可以通过伪造源 IP 的方式,这样服务器的响应就永远到达不了客户端(握手无法完成);

当然,通过设定客户端防火墙规则也可以达到同样的目的。

对 syn flood 实现拦截是比较困难的,可以通过启用 syn_cookies 的方式实现缓解,但这通常不是最佳方案。

最好的办法是通过专业的防火墙来解决,基本上所有的云计算大T 都具备这个能力。

问题3. 半连接队列和全连接队列如何调优

这里提到了一个"半连接队列"(syns queue),与其对应的还有一个 "全连接队列"(accept queue)

前者用于暂存未建立完全的连接,后者是连接在成功建立后进入的一个队列。

半连接队列默认大小可以通过内核参数调整:

  1. echo 4096 >  /proc/sys/net/ipv4/tcp_max_syn_backlog 

黑板:tcpmaxsynbacklog 在 syncookies 开启时是无效的,这两个选项存在冲突

对于全连接队列,如果服务器未能及时通过 accept 调用将其中的连接取走,会导致队列溢出(连接失效)

全连接队列的大小的内核调优方式:

  1. echo  4096 >  /proc/ sys/net/core/somaxconn 

那么,是不是只有内核调优这种方法能影响这两个参数呢?答案是否定的。

实际上,在应用层调用 socket listen 时也支持设置一个 backlog参数,这几个之间的关系如下:

  1. 半连接队列长度 = min(backlog,内核 net.core.somaxconn,内核 tcp_max_syn_backlog) 
  2. 全连接队列长度 = min(backlog,内核 net.core.somaxconn) 

黑板:一般的应用服务器如 netty、tomcat 都支持设置 backlog 参数,但是在真正进行调优时还需要配合考虑内核参数的配置。

五、 四次挥手

聊点 TCP 干货

在释放连接时,由于TCP是全双工的,因此最后要由两端分别进行关闭,这个流程如下:

  • 客户端发送一个FIN,用来关闭客户端到服务器的数据传送,客户端进入FINWAIT1状态。
  • 服务器收到FIN后,发送一个ACK给客户端,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),服务器进入CLOSEWAIT状态,而客户端进入FINWAIT2状态。
  • 服务器发送一个FIN,用来关闭服务器到客户端的数据传送,服务器进入LASTACK状态。
  • 客户端收到FIN后,客户端进入TIMEWAIT状态,接着发送一个ACK给服务器,确认序号为收到序号+1,服务器进入CLOSED状态,完成释放。

关闭连接有主动关闭和被动关闭一说,这里为了简化理解,我们以客户端作为主动关闭方,服务器为被动关闭方。

四次挥手需要关注的问题:

问题1. 为什么是四次挥手

发送FIN的一方就是主动关闭(客户端),而另一方则为被动关闭(服务器)。

当一方发送了FIN,则表示在这一方不再会有数据的发送。

其中当被动关闭方受到对方的FIN时,此时往往可能还有数据需要发送过去,因此无法立即发送FIN(也就是无法将FIN与ACK合并发送),

而是在等待自己的数据发送完毕后再单独发送FIN,因此整个过程需要四次交互。

问题2. 什么是半关闭

客户端在收到第一个FIN的ACK响应后,会进入FINWAIT2 状态时,此时服务器处于 CLOSEWAIT状态,这种状态就称之为半关闭。

从半关闭到全关闭,需要等待第二次FIN的确认才算结束。此时,客户端要等到服务器的FIN才能进入TIMEWAIT,

如果对方迟迟不发送FIN呢,则会等待一段时间后超时,这个可以通过内核参数tcpfin_timeout控制,默认是60s。

问题3. 为什么服务器会有大量 closewait

半关闭的状态下的服务器连接会处于 closewait 状态,直到服务器发送了FIN。

(编辑:衡阳站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读