版权声明:本文由胡文斌原创文章,转载请注明出处: 
文章原文链接:https://www.qcloud.com/community/article/102

来源:腾云阁 https://www.qcloud.com/community

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页):

  1. 可靠地实现TCP全双工连接的终止。(确保最后的ACK能让被关闭方接收)
  2. 允许老的重复分节在网络中消逝。(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关闭连接(为什么会能Time_wait,Close_wait?)的更多相关文章

  1. [TCP/IP] TCP关闭连接为什么四次挥手

    1.建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端. 2.而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据 ...

  2. tcp关闭连接:挥手讨论

    讨论焦点: 如果client发送FIN后,服务器端未返回完成的数据(缓存区中)还执行返回吗? 参考文档:https://download.csdn.net/download/u013547552/10 ...

  3. TCP的三次握手(建立连接)和四次挥手(关闭连接)

    参照: http://course.ccniit.com/CSTD/Linux/reference/files/018.PDF http://hi.baidu.com/raycomer/item/94 ...

  4. 关于TCP主动关闭连接中的wait_timeout

    首先我们先来回顾一下tcp关闭连接的过程: 假设A和B连接状态为EST,A需要主动关闭: A发送FIN给B,并将状态更改为FIN_WAIT1, B接收到FIN将状态更改为CLOSE_WAIT,并回复A ...

  5. TCP建立连接的3次握手和关闭连接的4次挥手

    #.3次握手过程状态 第一次握手:建立连接时,客户端发送SYN包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认: 第二次握手:服务器收到SYN包,必须确认客户的SYN(ack=j+ ...

  6. TCP三次握手(建立连接)/四次挥手(关闭连接)

    TCP数据包格式 顺序号(32位):用来标识从TCP源端向TCP目的端发送的数据字节流,它表示在这个报文段中的第一个数据字节的顺序号.如果将字节流看作在两个应用程序间的单向流动,则TCP用顺序号对每个 ...

  7. TCP的三次握手(建立连接)和四次挥手(关闭连接)(转)

    转自:(http://www.cnblogs.com/Jessy/p/3535612.html) 参照: http://course.ccniit.com/CSTD/Linux/reference/f ...

  8. 【转载】TCP的三次握手(建立连接)和四次挥手(关闭连接)

    建立连接: 理解:窗口和滑动窗口TCP的流量控制 TCP使用窗口机制进行流量控制 什么是窗口? 连接建立时,各端分配一块缓冲区用来存储接收的数据,并将缓冲区的尺寸发送给另一端 接收方发送的确认信息中包 ...

  9. 深入理解TCP建立和关闭连接

    建立连接: 理解:窗口和滑动窗口TCP的流量控制TCP使用窗口机制进行流量控制什么是窗口?连接建立时,各端分配一块缓冲区用来存储接收的数据,并将缓冲区的尺寸发送给另一端 接收方发送的确认信息中包含了自 ...

随机推荐

  1. Hive Tuning(一) 连接策略

    群里共享了一本hive调优的书记,名叫<Hive Tunning>,就忍不住开始看了,也顺便记录一下自己学到的东西,备忘! 首先,这是hive的数据摘要,别问我什么意思,我也没看懂. 好, ...

  2. DataGridView使用技巧十二:DataGridView Error图标表示的设定

    为了提醒用户注意,DataGridView可以使用Error图标来突出显示. Error图标可以在单元格和行头内表示,但不能在列头上显示. 1.ErrorText属性 当设定单元格/行的ErrorTe ...

  3. StarRTC , AndroidThings , 树莓派小车,公网环境,视频遥控(二)小车端

    原文地址:http://blog.starrtc.com/?p=94 1 创建工程IDE:Android Studio 3.1:File>New>New Project>输入项目名& ...

  4. Game Loop的几种实现方式

    http://www.bennychen.cn/2011/06/game-loop-model/ —————————————————————————————— 写这篇博客的目的是为了对game loo ...

  5. javax.naming.NoInitialContextException错误的解决方案

    今天,学习用了一下nutz框架,写了一个HelloWorld的小程序,在用jndi配置数据源时,写了一个测试类,并在main方法中调用了jndi获得数据库连接,但是报错了,错误信息如下: javax. ...

  6. 常用CSS缩写语法总结(转)

    使用缩写可以帮助减少你CSS文件的大小,更加容易阅读.css缩写的主要规则如下: 颜色 16进制的色彩值,如果每两位的值相同,可以缩写一半,例如:#000000可以缩写为#000;#336699可以缩 ...

  7. react新手入门(序)

    之前在软件园使用的是react,当时为了做个集光推送,自己去搭过react,这次项目中继续使用react,于是又重新操作了遍,恰巧公司买了本react的书籍,这本书写的非常好,看着并不觉得拗口,很容易 ...

  8. 3d引擎列表

    免费引擎 Agar - 一个高级图形应用程序框架,用于2D和3D游戏. Allegro library - 基于 C/C++ 的游戏引擎,支持图形,声音,输入,游戏时钟,浮点,压缩文件以及GUI. A ...

  9. 调整swap分区大小-Linux下安装Oracle时报swap不够解决方法

    调整swap分区大小 方法一:如果磁盘有剩余的空间,用分区工具新建一个swap分区.并写到/etc/fstab里面.再 #swapon -a方法二:可以用一个文件做交换分区. su root cd / ...

  10. BleedTree动画混合树

    通过Unity动画状态机,能帮我们轻松处理转换各个动画片断,达到想要的效果,但是如果仅仅是一个个动画的硬生生的切换,那么看起来就非常突然,而不真实了,在质量要求比较高的游戏中,特别是动作游戏,我们就不 ...