TCP关闭连接的方法是什么

86次阅读
没有评论

共计 2382 个字符,预计需要花费 6 分钟才能阅读完成。

这篇文章主要介绍“TCP 关闭连接的方法是什么”,在日常操作中,相信很多人在 TCP 关闭连接的方法是什么问题上存在疑惑,丸趣 TV 小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”TCP 关闭连接的方法是什么”的疑惑有所帮助!接下来,请跟着丸趣 TV 小编一起来学习吧!

Tcp 关闭连接问题及注意

最近一段时间一直在学习阅读 mina 和 nio 的源码,也发现了一些问题无法解决,然后重读了一下 tcp 协议,收获颇多。(这就是带着问题去读书的好处)

这次就和大家分享一下我们的 netframework 服务总会抛出一个“connet reset by peer”的原因吧。通过抓包工具分析,主动关闭方直接发送了一个 RST flags, 而非 FIN。就终止连接了。如下图所示:

为什么调用 sokcet 的 close 时只通过一次握手就终结连接了?

要分析这个原因那就得从关闭连接程的四次握手,有时也会是三次握手,说起。

大家都知道 tcp 正常的关闭连接要经过四次握手。如下所示:

在这四次握手状态中,有一个特别要注意的状态 TIME_WAIT。这个状态是主动关闭方在收到被关闭方的 FIN 后会处于并长期(2 个 MSL 时间,根据具体的实现不同,这个值会不同,在 RFC 1122 建议 MSL= 2 分钟,但在 Berkeley 的实现上使用的值为 30s, 具体可以看 www.rfc.net , 要是没有耐心去看英文的可以看这个网站 www.cnpaf.net  里面有协议说明以及相应的源码,java 源码中我没有发现这个值,我只能追踪到 PlainSocketImpl.java 这个类,再往下就是本地接口调用了,因此它是依赖本地操作系统的实现)处于的一个状态。也就是大约 1 - 4 分钟,然后由操作系统自动回收并将 TCP 连接设为 CLOSED 初始状态。如下图所示:

然而在 socket 的处于 TIME_WAIT 状态之后到它结束之前,该 socket 所占用的本地端口号将一直无法释放,因此服务在高并发高负载下运行一段时间后,就常常会出现做为客户端的程序无法向服务端建立新的 socket 连接的情况,过了 1~4 分钟之后,客户又可以连接上了,没多久又连接不上,再等 1~4 分钟之后又可以连接上,(上一个星期我们在做一个服务切换时遇到了这种情况)

这是因为服务方 socket 资源已经耗尽。netstat 命令查看系统将会发现机器上存在大量处于 TIME_WAIT 状态的 socket 连接, 我这边曾经出现达到了 2w 多个,并且占用大量的本地端口号。而此时机器上的可用本地端口号被占完,旧的大量处于 TIME_WAIT 状态的 socket 尚未被系统回收时,就会出现无法向服务端创建新的 socket 连接的情况。只能过 2 分钟之后等系统回收这些 socket 和端口资源之后才能服务,就这样往复下去。

TCP 为什么要这么要让这种 TIME_WAIT 状态存活这么久呢?其原因有两个(参考 stevens 的 unix 网络编程卷 1 第 38 页):

可靠地实现 TCP 全双工连接的终止。(确保最后的 ACK 能让被关闭方接收)

允许老的重复分节在网络中消逝。(TCP 中是可靠的服务,当数据包丢失会重传,当有数据包迷路的情况下,如果不等待 2MSL 时,当客户端以同样地方式重新和服务建立连接后,上一次迷路的数据包这时可能会到达服务,这时会造成旧包被重新读取)

解决方法:

1、(推荐方法,只能治标不治本)重用本地端口设置 SO_REUSEADDR 和 SO_REUSEPORT(stevens 的 unix 网络编程卷 1 第 179~182 页)有详情的讲解,这样就可以允许同一端口上启动同一服务器的多个实例。怎样理解呢?说白了就是即使 socket 断了,重新调用前面的 socket 函数不会再去占用新的一个,而是始终就是一个端口,这样防止 socket 始终连接不上,会不断地换新端口。Java 中通过调用 Socket 的 setReuseAddress, 详细可以查看 java.net.Socket 源码。【这个地方会有风险,具体可以看(stevens 的 unix 网络编程卷 1 第 181 页)】

2、修改内核 TIME_WAIT 等待的值,如果客户端和服务器都在同个路由器下,这个是非常推荐的。(链路好,重传机率低)

3、(不推崇,但目前我们是这样做的,这个是造成(“connet reset by peer”)的元凶)设置 SO_LINGER 的值,java 中是调用 socket 的 setSoLinger 目前我们是设置为 0 的。设置为这个值的意思是当主动关闭方设置了 setSoLinger(true,0)时,并调用 close 后,立该发送一个 RST 标志给对端,该 TCP 连接将立刻夭折,无论是否有排队数据未发送或未被确认。这种关闭方式称为“强行关闭”,而后套接字的虚电路立即被复位,尚未发出的所有数据都会丢失。而被动关闭方却不知道对端已经彻底断开。当被动关闭方正阻塞在 recv()调用上时,接受到 RST 时,会立刻得到一个“connet reset by peer”的异常(即对端已经关闭),c 中是返回一个 EPEERRST 错。

为什么不推崇这种方法在 (stevens 的 unix 网络编程卷 1 第 173 页) 有详细的讲解。因为 TIME_WAIT 状态是我们的朋友,它是有助有我们的(也就是说,它会让旧的重复分节在网络中超时消失(当我们的链路越长,ISP 复杂的情况下(从网通到教育网的 ping 包用了 9000ms),重复的分节的比例是非常高的。))。而且我们主动关闭连接方大都是由客户端发起的(除了 HTTP 服务和异常),而且客户方一般都不会有持续的大并发请求。因此对资源没有这么苛刻要求。

到此,关于“TCP 关闭连接的方法是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注丸趣 TV 网站,丸趣 TV 小编会继续努力为大家带来更多实用的文章!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-04发表,共计2382字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)