广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >CLOSE_WAIT状态解决方案
  • 219
分享到

CLOSE_WAIT状态解决方案

2024-04-02 19:04:59 219人浏览 安东尼
摘要

这个问题之前没有怎么留意过,是最近在面试过程中遇到的一个问题,面了两家公司,两家公司竟然都面到到了这个问题,不得不使我开始关注这个问题。说起CLOSE_WaiT状态,如果不知道的话,

这个问题之前没有怎么留意过,是最近在面试过程中遇到的一个问题,面了两家公司,两家公司竟然都面到到了这个问题,不得不使我开始关注这个问题。说起CLOSE_WaiT状态,如果不知道的话,还是先瞧一下tcp的状态转移图吧。

 

关闭Socket分为主动关闭(Active closure)和被动关闭(Passive closure)两种情况。前者是指有本地主机主动发起的关闭;而后者则是指本地主机检测到远程主机发起关闭之后,作出回应,从而关闭整个连接。将关闭部分的状态转移摘出来,就得到了下图:

TCP 状态变化

产生原因
通过图上,我们来分析,什么情况下,连接处于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
#define SERV_PORT 8000
 
int main(void)
{
    struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int listenfd, connfd;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];
    int i, n;
 
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
 
        int opt = 1;
        setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
 
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);
    
    bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
 
    listen(listenfd, 20);
 
    printf("Accepting connections ...\n");
    while (1) {
        cliaddr_len = sizeof(cliaddr);
        connfd = accept(listenfd, 
                (struct sockaddr *)&cliaddr, &cliaddr_len);
        //while (1) 
                {
            n = read(connfd, buf, MAXLINE);
            if (n == 0) {
                printf("the other side has been closed.\n");
                break;
            }
            printf("received from %s at PORT %d\n",
                   inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
                   ntohs(cliaddr.sin_port));
    
            for (i = 0; i < n; i++)
                buf[i] = toupper(buf[i]);
            write(connfd, buf, n);
        }
        //这里故意不关闭socket,或者是在close之前加上一个sleep都可以
        //sleep(5);
        //close(connfd);
    }
}

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
#define SERV_PORT 8000
 
int main(int arGC, char *argv[])
{
    struct sockaddr_in servaddr;
    char buf[MAXLINE];
    int sockfd, n;
    char *str;
    
    if (argc != 2) {
        fputs("usage: ./client message\n", stderr);
        exit(1);
    }
    str = argv[1];
    
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
 
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);
    
    connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
 
    write(sockfd, str, strlen(str));
 
    n = read(sockfd, buf, MAXLINE);
    printf("Response from server:\n");
    write(STDOUT_FILENO, buf, n);
    write(STDOUT_FILENO, "\n", 1);
 
    close(sockfd);
    return 0;
}

结果如下:


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));

到此这篇关于CLOSE_WAIT状态解决方案的文章就介绍到这了,更多相关CLOSE_WAIT状态内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: CLOSE_WAIT状态解决方案

本文链接: https://www.lsjlt.com/news/132710.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • CLOSE_WAIT状态解决方案
    这个问题之前没有怎么留意过,是最近在面试过程中遇到的一个问题,面了两家公司,两家公司竟然都面到到了这个问题,不得不使我开始关注这个问题。说起CLOSE_WAIT状态,如果不知道的话,...
    99+
    2022-11-12
  • CLOSE_WAIT状态的原因与解决方法
    CLOSE_WAIT状态是TCP连接的一种状态,表示本地端已经发起了关闭连接的请求,但是远程端还没有发送关闭连接的响应。原因:1. 本地端发送了关闭连接的请求,但是远程端还没有收到或者没有及时响应。2. 远程端正在处理其他任务,导致无法...
    99+
    2023-08-11
    CLOSE_WAIT
  • 关于close_wait状态的理解
    close_wait状态是TCP/IP协议中的一种状态,它表示在一个TCP连接中,一方已经发送了关闭连接的请求,但是另一方还没有完全...
    99+
    2023-09-06
    close_wait
  • java状态机方案解决订单状态扭转示例详解
    目录状态机机制定义订单状态定义状态机配置定义事件创建状态机处理状态机事件创建一个订单状态机确定状态和事件设计状态转移图实现状态机状态机机制 状态机机制是一种常用的解决状态扭转问题的...
    99+
    2023-03-07
    java解决订单状态扭转 java 状态机
  • 阿里云服务器备案异常状态解决方法
    在使用阿里云服务器的过程中,可能会遇到服务器备案异常状态的问题。本文将详细介绍如何解决这个问题,帮助用户顺利使用阿里云服务器。 一、什么是阿里云服务器备案异常状态阿里云服务器备案异常状态是指在阿里云服务器上注册的域名没有完成备案,而阿里云服...
    99+
    2023-11-14
    阿里 解决方法 异常
  • 解析HTTP协议中4xx状态码的使用案例与解决方法
    探索HTTP协议中4xx状态码的应用场景和解决方案引言:在Web开发中,HTTP协议起着非常重要的作用。它定义了客户端和服务器之间进行通信的规则和约定。其中,状态码是服务器用来向客户端传达请求处理情况的一种标识。在HTTP协议中,4xx状态...
    99+
    2023-12-26
    应用场景 解决方案 xx状态码
  • vuex闲置状态的重置方案
    本篇内容介绍了“vuex闲置状态的重置方案”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!前言大型单页应用(...
    99+
    2022-10-19
  • 分析Python感知线程状态的解决方案之Event与信号量
    目录一、停止线程二、线程信号的传递三、信号量四、总结一、停止线程 利用Threading库我们可以很方便地创建线程,让它按照我们的想法执行我们想让它执行的事情,从而加快程序运行的效率。然而有一点坑爹的是,线程创建之后...
    99+
    2022-06-02
    python 感知线程状态 python Event python 信号量
  • Ajax 请求队列解决方案并结合elementUi做全局加载状态
    目录ajax 文件入口消息队列elementUi loading参数设置基于elementUI的loading全局加载应用场景1.引入库2.定义全局loading3.使用ajax 文...
    99+
    2022-11-13
    Ajax 请求队列 elementUi全局加载
  • JS技巧多状态页面中的mock方案详解
    目录引言技术选型业务逻辑改造Eruda 插件Mock 数据整理引言 我们有时候会遇到一个业务页面存在很多个状态,甚至子状态,比如订单详情就是其中的典型,涉及从订单创建到订单结束,以...
    99+
    2023-01-13
    JS 多状态页面mock 多状态页面mock
  • 详解iOS中跨页面状态同步方案比较
    由于团队希望项目能够去 CoreData 化,而以往状态同步都是依赖于 CoreData 的NSFetchedResultsController。因此去 CoreData 则必须寻找...
    99+
    2022-05-19
    iOS 跨页面 同步
  • Android端内数据状态同步方案VM-Mapping详解
    目录背景问题拆解目标方案调研EventBus基于k-v的监听、通知全局共享数据Model实例基于注解的对象映射方案VM-Mapping特点思考突破View层级的限制突破类型的限制详细...
    99+
    2022-11-12
  • SpringBoot循环依赖的症状和解决方案
    目录什么是循环依赖?问题及症状ComponentAComponentB错误解决方法构造器注入的案例延迟注入的案例接口隔离的案例什么是循环依赖? 循环依赖是指在Spring Boot ...
    99+
    2023-05-15
    Java SpringBoot循环依赖 SpringBoot循环依赖 解决SpirngBoot循环依赖
  • 如何优化vuex的状态管理方案
    这篇文章主要为大家展示了“如何优化vuex的状态管理方案”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何优化vuex的状态管理方案”这篇文章吧。在 vuejs...
    99+
    2022-10-19
  • Vista 无法进入睡眠状态的解决方法
    实际上这是个非常简单的问题,但是很多新手朋友们很困惑,睡眠也好,休眠也好,都要往硬盘里面写入几个G的文件的一般,下面来看看软媒论坛网友的问题和我们的解答。   问:请问为什么我的笔记本电脑无法进入睡眠状态呢?以前刚装好V...
    99+
    2023-05-25
    Vista 无法进入睡眠 睡眠 解决 无法 方法
  • vue的状态更新方式(异步更新解决)
    目录状态更新(异步更新解决)解决方案异步更新及nexttick为什么需要异步更新nextTick 原理状态更新(异步更新解决) 在vue中状态更新是异步的,这一点和react中的se...
    99+
    2022-11-13
  • Oracle 11g RAC中INTERMEDIATE Stuck Archiver状态的解决方法
    这篇文章给大家介绍Oracle 11g RAC中INTERMEDIATE Stuck Archiver状态的解决方法,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。 新建的库,空跑了几...
    99+
    2022-10-19
  • vue中v-for数据状态值变了,但是视图没改变的解决方案
    目录v-for数据状态值变了,但是视图没改变问题现象问题出现原因问题解决v-for循环改变循环数据视图不更新解决1解决2v-for数据状态值变了,但是视图没改变 问题现象 1.你在v...
    99+
    2022-11-13
  • windows状态栏卡住如何解决
    本文小编为大家详细介绍“windows状态栏卡住如何解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“windows状态栏卡住如何解决”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。方法一: 首先按下快捷键“ct...
    99+
    2023-07-02
  • windows状态栏死机如何解决
    今天小编给大家分享一下windows状态栏死机如何解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。首先按下快捷键“ctrl...
    99+
    2023-07-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作