聊点TCP干货
在建立TCP连接时,需要经过三次交互,也成为三次握手(HandShake)。
在谈论三次握手的时候,有几个问题是需要关注的: 问题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) 前者用于暂存未建立完全的连接,后者是连接在成功建立后进入的一个队列。 半连接队列默认大小可以通过内核参数调整:
黑板:tcpmaxsynbacklog 在 syncookies 开启时是无效的,这两个选项存在冲突 对于全连接队列,如果服务器未能及时通过 accept 调用将其中的连接取走,会导致队列溢出(连接失效) 全连接队列的大小的内核调优方式:
那么,是不是只有内核调优这种方法能影响这两个参数呢?答案是否定的。 实际上,在应用层调用 socket listen 时也支持设置一个 backlog参数,这几个之间的关系如下:
黑板:一般的应用服务器如 netty、tomcat 都支持设置 backlog 参数,但是在真正进行调优时还需要配合考虑内核参数的配置。 五、 四次挥手 在释放连接时,由于TCP是全双工的,因此最后要由两端分别进行关闭,这个流程如下:
关闭连接有主动关闭和被动关闭一说,这里为了简化理解,我们以客户端作为主动关闭方,服务器为被动关闭方。 四次挥手需要关注的问题: 问题1. 为什么是四次挥手 发送FIN的一方就是主动关闭(客户端),而另一方则为被动关闭(服务器)。 当一方发送了FIN,则表示在这一方不再会有数据的发送。 其中当被动关闭方受到对方的FIN时,此时往往可能还有数据需要发送过去,因此无法立即发送FIN(也就是无法将FIN与ACK合并发送), 而是在等待自己的数据发送完毕后再单独发送FIN,因此整个过程需要四次交互。 问题2. 什么是半关闭 客户端在收到第一个FIN的ACK响应后,会进入FINWAIT2 状态时,此时服务器处于 CLOSEWAIT状态,这种状态就称之为半关闭。 从半关闭到全关闭,需要等待第二次FIN的确认才算结束。此时,客户端要等到服务器的FIN才能进入TIMEWAIT, 如果对方迟迟不发送FIN呢,则会等待一段时间后超时,这个可以通过内核参数tcpfin_timeout控制,默认是60s。 问题3. 为什么服务器会有大量 closewait 半关闭的状态下的服务器连接会处于 closewait 状态,直到服务器发送了FIN。 (编辑:PHP编程网 - 黄冈站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |