CLOSE_WAIT状态的原因与解决方法 --转
转自:http://blog.chinaunix.net/uid-20357359-id-1963662.html
这个问题之前没有怎么留意过,是最近在面试过程中遇到的一个问题,面了两家公司,两家公司竟然都面到到了这个问题,不得不使我开始关注这个问题。说起CLOSE_WAIT状态,如果不知道的话,还是先瞧一下TCP的状态转移图吧。
关闭socket分为主动关闭(Active closure)和被动关闭(Passive closure)两种情况。前者是指有本地主机主动发起的关闭;而后者则是指本地主机检测到远程主机发起关闭之后,作出回应,从而关闭整个连接。将关闭部分的状态转移摘出来,就得到了下图:
产生原因
通过图上,我们来分析,什么情况下,连接处于CLOSE_WAIT状态呢?
在被动关闭连接情况下,在已经接收到FIN,但是还没有发送自己的FIN的时刻,连接处于CLOSE_WAIT状态。
通常来讲,CLOSE_WAIT状态的持续时间应该很短,正如SYN_RCVD状态。但是在一些特殊情况下,就会出现连接长时间处于CLOSE_WAIT状态的情况。
出现大量close_wait的现象,主要原因是某种情况下对方关闭了socket链接,但是我方忙与读或者写,没有关闭连接。代码需要判断socket,一旦读到0,断开连接,read返回负,检查一下errno,如果不是AGAIN,就断开连接。
参考资料4中描述,通过发送SYN-FIN报文来达到产生CLOSE_WAIT状态连接,没有进行具体实验。不过个人认为协议栈会丢弃这种非法报文,感兴趣的同学可以测试一下,然后把结果告诉我;-)
为了更加清楚的说明这个问题,我们写一个测试程序,注意这个测试程序是有缺陷的。
只要我们构造一种情况,使得对方关闭了socket,我们还在read,或者是直接不关闭socket就会构造这样的情况。
server.c:
#include <stdio.h> #include <string.h> #include <netinet/in.h> #define MAXLINE 80 int main(void) listenfd = socket(AF_INET, SOCK_STREAM, 0); int opt = 1; bzero(&servaddr, sizeof(servaddr)); listen(listenfd, 20); printf("Accepting connections ...\n"); |
client.c:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #define MAXLINE 80 int main(int argc, char *argv[]) bzero(&servaddr, sizeof(servaddr)); write(sockfd, str, strlen(str)); n = read(sockfd, buf, MAXLINE); close(sockfd); |
结果如下:
debian-wangyao:~$ ./client a Response from server: A debian-wangyao:~$ ./client b Response from server: B debian-wangyao:~$ ./client c Response from server: C debian-wangyao:~$ netstat -antp | grep CLOSE_WAIT (Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.) tcp 1 0 127.0.0.1:8000 127.0.0.1:58309 CLOSE_WAIT 6979/server tcp 1 0 127.0.0.1:8000 127.0.0.1:58308 CLOSE_WAIT 6979/server tcp 1 0 127.0.0.1:8000 127.0.0.1:58307 CLOSE_WAIT 6979/server |
解决方法
基本的思想就是要检测出对方已经关闭的socket,然后关闭它。
1.代码需要判断socket,一旦read返回0,断开连接,read返回负,检查一下errno,如果不是AGAIN,也断开连接。(注:在UNP 7.5节的图7.6中,可以看到使用select能够检测出对方发送了FIN,再根据这条规则就可以处理CLOSE_WAIT的连接)
2.给每一个socket设置一个时间戳last_update,每接收或者是发送成功数据,就用当前时间更新这个时间戳。定期检查所有的时间戳,如果时间戳与当前时间差值超过一定的阈值,就关闭这个socket。
3.使用一个Heart-Beat线程,定期向socket发送指定格式的心跳数据包,如果接收到对方的RST报文,说明对方已经关闭了socket,那么我们也关闭这个socket。
4.设置SO_KEEPALIVE选项,并修改内核参数
前提是启用socket的KEEPALIVE机制:
//启用socket连接的KEEPALIVE
int iKeepAlive = 1;
setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *)&iKeepAlive, sizeof(iKeepAlive));
tcp_keepalive_intvl (integer; default: 75; since Linux 2.4)
The number of seconds between TCP keep-alive probes.
tcp_keepalive_probes (integer; default: 9; since Linux 2.2)
The maximum number of TCP keep-alive probes to send before giving up and killing the connection if no response is obtained from the other end.
tcp_keepalive_time (integer; default: 7200; since Linux 2.2)
The number of seconds a connection needs to be idle before TCP begins sending out keep-alive probes. Keep-alives are only sent when the SO_KEEPALIVE socket option is enabled. The default value is 7200 seconds (2 hours). An idle connec‐tion is terminated after approximately an additional 11 minutes (9 probes an interval of 75 seconds apart) when keep-alive is enabled.
echo 120 > /proc/sys/net/ipv4/tcp_keepalive_time
echo 2 > /proc/sys/net/ipv4/tcp_keepalive_intvl
echo 1 > /proc/sys/net/ipv4/tcp_keepalive_probes
除了修改内核参数外,可以使用setsockopt修改socket参数,参考man 7 socket。
int KeepAliveProbes=1; int KeepAliveIntvl=2; int KeepAliveTime=120; setsockopt(s, IPPROTO_TCP, TCP_KEEPCNT, (void *)&KeepAliveProbes, sizeof(KeepAliveProbes)); setsockopt(s, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&KeepAliveTime, sizeof(KeepAliveTime)); setsockopt(s, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&KeepAliveIntvl, sizeof(KeepAliveIntvl)); |
参考:
http://blog.chinaunix.net/u/20146/showart_1217433.html
http://blog.csdn.net/eroswang/archive/2008/03/10/2162986.aspx
http://haka.sharera.com/blog/BlogTopic/32309.htm
http://learn.akae.cn/media/ch37s02.html
http://faq.csdn.net/read/208036.html
http://www.cndw.com/tech/server/2006040430203.asp
http://davidripple.bokee.com/1741575.html
http://doserver.net/post/keepalive-linux-1.php
man 7 tcp
CLOSE_WAIT状态的原因与解决方法 --转的更多相关文章
- CLOSE_WAIT状态的原因与解决方法(转载留自己看)
这个问题之前没有怎么留意过,是最近在面试过程中遇到的一个问题,面了两家公司,两家公司竟然都面到到了这个问题,不得不使我开始关注这个问题.说起CLOSE_WAIT状态,如果不知道的话,还是先瞧一下TCP ...
- CLOSE_WAIT状态的原因与解决方法
https://blog.csdn.net/Windgs_YF/article/details/83513696 netstat -nat|awk '{print $6}'|sort|uniq -c| ...
- coreseek常见错误原因及解决方法
coreseek常见错误原因及解决方法 Coreseek 中文全文检索引擎 Coreseek 是一款中文全文检索/搜索软件,以GPLv2许可协议开源发布,基于Sphinx研发并独立发布,专攻中文搜索和 ...
- Linux的僵尸进程产生原因及解决方法
Linux的僵尸进程产生原因及解决方法: 1. 产生原因: 在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他,那么他将变成一个僵尸进程.通过ps命令查看 ...
- 需要我们了解的SQL Server阻塞原因与解决方法
需要我们了解的SQL Server阻塞原因与解决方法 上篇说SQL Server应用模式之OLTP系统性能分析.五种角度分析sql性能问题.本章依然是SQL性能 五种角度其一“阻塞与死锁” 这里通过连 ...
- Apache -- XAMPP Apache 无法启动原因及解决方法
XAMPP Apache 无法启动原因1(缺少VC运行库): 这个就是我遇到的问题原因,下载安装的XAMPP版本是xampp-win32-1.7.7-VC9,而现有的Windows XP系统又没有安装 ...
- php大文件上传失败的原因及解决方法
为什么上传大文件总是失败,上传小文件就没有问题.关于PHP大文件上传失败的原因及解决方法如下: 第1种情况:文件上传时存放文件的临时目录必须是开启的并且是 PHP 进程所有者用户可写的目录.如果未指定 ...
- Tomcat启动慢的原因及解决方法
Tomcat启动慢的原因及解决方法 在CentOS启动Tomcat时,启动过程很慢,需要几分钟,经过查看日志,发现耗时在这里:是session引起的随机数问题导致的.Tocmat的Session ID ...
- 交换机出现err-disable的原因及解决方法
转:https://www.2cto.com/net/201303/198724.html 交换机出现err-disable的原因及解决方法 LOG示例: 21w6d: %ETHCNTR-3-LOOP ...
随机推荐
- virsh console使用方法
How to use virsh console virsh 是libvirt 开源函数库中的一个命令行工具,用来在命令行下通过libvirt发布管理虚拟机的各种命令,现在介绍一下其中一个命令的使用方 ...
- C#中的OLEDB连接2
在通过ADO对Excel对象进行连接时(此时Excel则认为是一个数据源),需要配置对Excel数据源对应的连接串,这个连接串中包括了Provider信息(其实类似对数据库进行连接操作时,都需要指定连 ...
- mplayer windows configure修改
相信大家在编译mplayer的时候,都会遇到一个问题,就是那个折腾人的mplayer会检测当面目录下有没有ffmpeg的文件夹. 没有的话,mplayer会启动git进行漫长的下载ffmpeg源码.其 ...
- (Deep) Neural Networks (Deep Learning) , NLP and Text Mining
(Deep) Neural Networks (Deep Learning) , NLP and Text Mining 最近翻了一下关于Deep Learning 或者 普通的Neural Netw ...
- 用 C# 读取二进制文件
当想到所有文件都转换为 XML时,确实是一件好事.但是,这并非事实.仍旧还有大量的文件格式不是XML,甚至也不是ASCII.二进制文件仍然在网络中传播,储存在磁盘上,在应用程序之间传递.相比之下,在处 ...
- 7 个面向Web开发者的实用CSS3教程推荐
通过CSS来创建精细.复杂的效果,成为了Web前端开发的未来趋势.世界各地的设计师认为CSS3是一项非常具有潜力的技术,未来将会创造更多不可思议的美妙设计. 本文为Web开发者带来了一些与CSS3相关 ...
- BZOJ_1606_ [Usaco2008_Dec]_Hay_For_Sale _购买干草_(背包)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1606 价值和重量相等的01背包问题. 分析 ... #include <bits/std ...
- nginx-rrd监控nginx访问数
一 .查看已安装的nginx是否包含stub_status模块 /usr/local/nginx/sbin/nginx -V nginx version: Nginx/1.2.0 configure ...
- eclipse简单注释规范
设置注释模板的入口: Window->Preference->Java->Code Style->Code Template Types/*** @ClassName: ${t ...
- ubuntu usb权限问题解决
在/etc/udev/rules.d/ 创建51-android.rules SUBSYSTEM==" SUBSYSTEM=="