首先要明白close_wait状态是在tcp通信四次握手时的一个中间状态:

                      

即当被动关闭方发送完ACK后进入的状态。这个状态的结束,即要达到下一个状态LASK_ACK需要在发无端发送完剩余的数据后(send)、调用close函数之后。

下面我们模拟这种情况,即服务端发送完剩余的数据后,并没有调用close函数:

client端代码:

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> #define MAXLINE 80
#define SERV_PORT 8000 int main(int argc, char *argv[])
{
    struct sockaddr_in servaddr;
    char str[MAXLINE] = "test ";
    int sockfd, n; while()
{
sockfd = socket(AF_INET, SOCK_STREAM, );     bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "192.168.254.26", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT); connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
write(sockfd, str, strlen(str)); close(sockfd);
sleep();
}     return ;
}

server端代码:

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream> #include <sys/mman.h>
#include <sys/stat.h>        /* For mode constants */
#include <fcntl.h>           /* For O_* constants */ #include <unistd.h>
#include <arpa/inet.h> using namespace std; #define LENGTH 128
#include "netinet/in.h"
#define MAXLINE 80
#define SERV_PORT 8000 int main(int argc,char** argv)
{
struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int listenfd;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];
    //int i, n;
    int  n; //创建socket
    listenfd = socket(AF_INET, SOCK_STREAM, ); //设置端口重用
    int opt = ;
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));     //fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK);     bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET; inet_pton(AF_INET,"192.168.254.26",&(servaddr.sin_addr.s_addr));
    //servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);     bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));     listen(listenfd, );     printf("Accepting connections ...\n");
    while ()
{
        cliaddr_len = sizeof(cliaddr);
        int connfd = accept(listenfd,
                (struct sockaddr *)&cliaddr, &cliaddr_len); //while(1)
{
        n = recv(connfd, buf, MAXLINE,);
        if (n == )
{
//对端主动关闭
            printf("the other side has been closed.\n");
            //break;
        }
        printf("received from %s at PORT %d len = %d\n",
               inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
               ntohs(cliaddr.sin_port),n);
}
        //测试:模拟CLOSE_WAIT状态时,将close(connfd);这句代码注释         //close(connfd);
    }   return ;
}

测试代码中,当recv的返回值为0时(对端主动关闭连接),会跳出while(1)循环,此时正确做法是调用close关闭tcp连接

此处我们为了测试,故意将close(connfd)这句代码注释掉,注释后服务器对于客户端发送的FIN包不会做回应,一直保持close_wait状态。

运行截图:

如果将大量CLOSE_WAIT的解决办法总结为一句话那就是:查代码。因为问题出在服务器程序中。

------------------分割线----------------------

转自:https://blog.51cto.com/jin771998569/1688253

一、“多半是程序的原因”?这个还是交给程序猿吧

二、linux 下 CLOSE_WAIT过多的解决方法

情景描述:系统产生大量“Too many open files” 

原因分析:在服务器与客户端通信过程中,因服务器发生了socket未关导致的closed_wait发生,致使监听port打开的句柄数到了1024个,且均处于close_wait的状态,最终造成配置的port被占满出现“Too many open files”,无法再进行通信。

close_wait状态出现的原因是被动关闭方未关闭socket造成

解决办法:有两种措施可行

一、解决:

原因是因为调用ServerSocket类的accept()方法和Socket输入流的read()方法时会引起线程阻塞,所以应该用setSoTimeout()方法设置超时(缺省的设置是0,即超时永远不会发生);超时的判断是累计式的,一次设置后,每次调用引起的阻塞时间都从该值中扣除,直至另一次超时设置或有超时异常抛出。

比如,某种服务需要三次调用read(),超时设置为1分钟,那么如果某次服务三次read()调用的总时间超过1分钟就会有异常抛出,如果要在同一个Socket上反复进行这种服务,就要在每次服务之前设置一次超时。

二、规避:

调整系统参数,包括句柄相关参数和TCP/IP的参数;

注意:

/proc/sys/fs/file-max 是整个系统可以打开的文件数的限制,由sysctl.conf控制;

ulimit修改的是当前shell和它的子进程可以打开的文件数的限制,由limits.conf控制;

lsof是列出系统所占用的资源,但是这些资源不一定会占用打开文件号的;比如:共享内存,信号量,消息队列,内存映射等,虽然占用了这些资源,但不占用打开文件号;

因此,需要调整的是当前用户的子进程打开的文件数的限制,即limits.conf文件的配置;

如果cat /proc/sys/fs/file-max值为65536或甚至更大,不需要修改该值;

若ulimit -a ;其open files参数的值小于4096(默认是1024), 则采用如下方法修改open files参数值为8192;方法如下:

1.使用root登陆,修改文件/etc/security/limits.conf

vim /etc/security/limits.conf
 

添加

xxx - nofile 8192

xxx 是一个用户,如果是想所有用户生效的话换成 * ,设置的数值与硬件配置有关,别设置太大了。

#<domain>     <type>   <item>       <value>
* soft nofile 8192
* hard nofile 8192
 

#所有的用户每个进程可以使用8192个文件描述符。

2.使这些限制生效

确定文件/etc/pam.d/login 和/etc/pam.d/sshd包含如下行:

session required pam_limits.so

然后用户重新登陆一下即可生效。

3. 在bash下可以使用ulimit -a 参看是否已经修改:

一、 修改方法:(暂时生效,重新启动服务器后,会还原成默认值)

sysctl -w net.ipv4.tcp_keepalive_time=600
sysctl -w net.ipv4.tcp_keepalive_probes=2
sysctl -w net.ipv4.tcp_keepalive_intvl=2
 

注意:Linux的内核参数调整的是否合理要注意观察,看业务高峰时候效果如何。

二、 若做如上修改后,可起作用;则做如下修改以便永久生效。

vi /etc/sysctl.conf

若配置文件中不存在如下信息,则添加:

net.ipv4.tcp_keepalive_time = 1800
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl = 15
 

编辑完 /etc/sysctl.conf,要重启network 才会生效

/etc/rc.d/init.d/network restart

然后,执行sysctl命令使修改生效,基本上就算完成了。

------------------------------------------------------------

修改原因:

当客户端因为某种原因先于服务端发出了FIN信号,就会导致服务端被动关闭,若服务端不主动关闭socket发FIN给Client,此时服务端Socket会处于CLOSE_WAIT状态(而不是LAST_ACK状态)。通常来说,一个CLOSE_WAIT会维持至少2个小时的时间(系统默认超时时间的是7200秒,也就是2小时)。如果服务端程序因某个原因导致系统造成一堆CLOSE_WAIT消耗资源,那么通常是等不到释放那一刻,系统就已崩溃。因此,解决这个问题的方法还可以通过修改TCP/IP的参数来缩短这个时间,于是修改tcp_keepalive_*系列参数

tcp_keepalive_time:

/proc/sys/net/ipv4/tcp_keepalive_time

INTEGER,默认值是7200(2小时)

当keepalive打开的情况下,TCP发送keepalive消息的频率。建议修改值为1800秒。

tcp_keepalive_probes:INTEGER

/proc/sys/net/ipv4/tcp_keepalive_probes

INTEGER,默认值是9

TCP发送keepalive探测以确定该连接已经断开的次数。(注意:保持连接仅在SO_KEEPALIVE套接字选项被打开是才发送.次数默认不需要修改,当然根据情形也可以适当地缩短此值.设置为5比较合适)

tcp_keepalive_intvl:INTEGER

/proc/sys/net/ipv4/tcp_keepalive_intvl

INTEGER,默认值为75

当探测没有确认时,重新发送探测的频度。探测消息发送的频率(在认定连接失效之前,发送多少个TCP的keepalive探测包)。乘以tcp_keepalive_probes就得到对于从开始探测以来没有响应的连接杀除的时间。默认值为75秒,也就是没有活动的连接将在大约11分钟以后将被丢弃。(对于普通应用来说,这个值有一些偏大,可以根据需要改小.特别是web类服务器需要改小该值,15是个比较合适的值)。

1. 系统不再出现“Too many open files”报错现象。

2. 处于TIME_WAIT状态的sockets不会激长。

在 Linux 上可用以下语句看了一下服务器的TCP状态(连接状态数量统计):

netstat -n| awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

关于TCP中的keepalive机制,参考博客:
https://www.cnblogs.com/lidabo/p/3804108.html
http://www.importnew.com/27624.html
等有时间需要做一下整理。
 



【网络编程】服务端产生大量的close_wait状态的进程分析的更多相关文章

  1. Unity网络斗地主 服务端

    Unity网络斗地主  服务端 @by梦想之家2工作室 阿龙 已经做好了服务器框架,并且能实现服务器给客户端分牌的问题!

  2. 经典!服务端 TCP 连接的 TIME_WAIT 过多问题的分析与解决

    开源Linux 专注分享开源技术知识 本文给出一个 TIME_WAIT 状态的 TCP 连接过多的问题的解决思路,非常典型,大家可以好好看看,以后遇到这个问题就不会束手无策了. 问题描述 模拟高并发的 ...

  3. Linux网络编程——原始套接字实例:MAC 头部报文分析

    通过<Linux网络编程——原始套接字编程>得知,我们可以通过原始套接字以及 recvfrom( ) 可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢? 链路层封包格式 M ...

  4. C#开发BIMFACE系列13 服务端API之获取转换状态

    系列目录     [已更新最新开发文章,点击查看详细] 在<C#开发BIMFACE系列12 服务端API之文件转换>中详细介绍了7种文件转换的方法.发起源文件/模型转换后,转换过程可能成功 ...

  5. TCP之 TIME_WAIT和CLOSE_WAIT 状态 的原因分析和处理

    转自:http://blog.csdn.net/shootyou/article/details/6622226 昨天解决了一个HttpClient调用错误导致的服务器异常,具体过程如下: http: ...

  6. boost库在工作(37)网络UDP服务端之七

    前面介绍的都是网络TCP的服务器和客户端,其实还有UDP的服务器和客户端,同时也有同步和异步之分.UDP与TCP最大的区别,就是TCP是基于连接的,而UDP是无连接的.这里所谓的连接是指对方中断服务时 ...

  7. Legacy Notes网络和服务端配置的笔记

    在云服务器上使用LAMP全过程: 第一步:传文件 在windows上下载winscp,连接使用scp协议.注意:centos需要安装scp yum install openssh-clients 即可 ...

  8. python 学习笔记_2 模拟socket编程 服务端、客户端通信(参考核心编程2代码实现)

    服务器端代码实现: #!/usr/bin/env python#coding=gbk'''接收客户端字符串,在字段串前面打上当前时间,然后返回server端采用 python2 linux下调试运行客 ...

  9. 网络编程-SOCKET开发之----2. TCP粘包现象产生分析

    1. 粘包现象及产生原因 1)概念 指TCP协议中,发送方发送的若干个包数据到接收方接收时粘成一包.发送方粘包:发送方把若干个要发送的数据包封装成一个包,一次性发送,减少网络IO延迟:接收方粘包:接收 ...

随机推荐

  1. python------面向对象进阶反射详解(重点)

    一.反射 通过字符串映射或者修改程序运行时的状态,属性,或者方法. 1.getattr(object,name,default=None) 2.hasattr(object,name) 3.setat ...

  2. c# android 全局捕获未处理异常

    [Application] public class MyApp : Application { public MyApp(IntPtr javaReference, JniHandleOwnersh ...

  3. 用Redis存储Tomcat集群的Session实现session共享

    一.存储 前段时间,我花了不少时间来寻求一种方法,把新开发的代码推送到到生产系统中部署,生产系统要能够零宕机.对使用用户零影响. 我的设想是使用集群来搞定,通过通知负载均衡Nginx,取下集群中的To ...

  4. [JAVA]为什么==和equals总让新手迷惑? 详解 关系操作符 == 和 equals

    关系操作符==和 类的equals方法都可以用来比较两个类是否相同,但实际用起来却经常产生令JAVA新手迷惑的结果. 先看一段示例代码: public class HelloWorld { publi ...

  5. C# datagridview大小跟随窗口动态改变(转)

    在C#中使用winform布局的时候,拖一个datagridview到窗体上面,将datagridview调整为适合窗体的大小. 但是运行之后,点击最大化按钮的时候,发现datagridview的大小 ...

  6. 请确保 ASP.NET State Service (ASP.NET 状态服务)已启动 问题解决

    当iis部署的网站访问遇到如下错误时: 无法向会话状态服务器发出会话状态请求.请确保 ASP.NET State Service (ASP.NET 状态服务)已启动,并且客户端端口与服务器端口相同.如 ...

  7. TreeSet的两种排序方式,含Comparable、Comparator

    1.排序的引入 由于TreeSet可以实现对元素按照某种规则进行排序,例如下面的例子 public class TreeSetDemo { public static void main(String ...

  8. <亲测>CentOS中yum安装ffmpeg

    CentOS中yum安装ffmpeg 1.升级系统 sudo yum install epel-release -y sudo yum update -y sudo shutdown -r now 2 ...

  9. Lock和synchronized的区别和使用

    Java并发编程:Lock 今天看了并发实践这本书的ReentantLock这章,感觉对ReentantLock还是不够熟悉,有许多疑问,所有在网上找了很多文章看了一下,总体说的不够详细,重点和焦点问 ...

  10. c++ :

    (1)表示机构内位域的定义(即该变量占几个bit空间)   typedef struct _XXX{ unsigned char a:4; unsigned char c; } ; XXX