一周一更之RESET

前因

最近遇到一个问题:在存在防火墙的情况下,某些客户端在某个时间段连接服务器时会出现连接不上的问题,在客户端侧用wireshark抓包发现,在进行tcp三次握手过程中,对于客户端的第一个SYN,服务器端总以RST响应。

分析

年少不懂事的我,一开始以为是防火墙的问题,但是该同一源地址的客户端便会出现这种情况,应该也就排除了这种情况,防火墙的规则基本上是不会更改的。此路不通,便想到了是不是服务端监听的那一路连接是不是主动发送了FIN,进入到TIME_WAIT的状态。此时其他的客户端再进行连接时,就会收到服务端的RST响应。为了证实这种情况下,是符合的这种现象,构造了下面简单的demo程序,由于只是简单的程序,很多异常并没有考虑。

客户端程序:

/**
* client.c
**/

#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/select.h>
#include <sys/time.h>


int main(int argc, char *argv[])
{
    int n, sockfd;
    char *pBuf = "HI,SERVER";
    struct sockaddr_in stServer;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == sockfd)
    {
        printf("socket failed,reason[%s]\n", strerror(errno));
        return -1;
    }

    memset(&stServer, 0, sizeof(stServer));
    stServer.sin_family = AF_INET;
    stServer.sin_port = htons(9999);
    inet_pton(AF_INET, argv[1], &stServer.sin_addr);

    if( -1 == (connect(sockfd, (struct sockaddr *)&stServer, sizeof(stServer))))
    {
        printf("connect failed,reason[%s]\n", strerror(errno));
        return -1;
    }

    n = write(sockfd, pBuf, strlen(pBuf));

    /**
    * 等待server发送FIN后再FIN
    **/
    sleep(5);

    return 0;

}

服务端程序:

/**
* server.c
**/

#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/select.h>
#include <sys/time.h>


int main()
{
    size_t len;
    int sockfd, acceptfd, n;
    char buf[1024] = {0};
    struct sockaddr_in stServer,stCliet;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == sockfd)
    {
        printf("socket failed,reason[%s]\n", strerror(errno));
        return -1;
    }

    memset(&stServer, 0, sizeof(stServer));
    stServer.sin_family = AF_INET;
    stServer.sin_port = htons(9999);
    stServer.sin_addr.s_addr = htonl(INADDR_ANY);

    if(-1 == bind(sockfd, (struct sockaddr *)&stServer, sizeof(stServer)))
    {
        printf("bind failed,reason[%s]\n", strerror(errno));
        return -1;
    }

    if(-1 == listen(sockfd, 8))
    {
        printf("listen failed,reason[%s]\n", strerror(errno));
        return -1;
    }

    memset(&stCliet, 0, sizeof(stCliet));
    len = sizeof(stCliet);

    acceptfd = accept(sockfd, (struct sockaddr *)&stCliet, &len);
    if(-1 == acceptfd)
    {
        printf("acceptfd failed,reason[%s]\n", strerror(errno));
        return -1;
    }

    n = read(acceptfd, buf, 1023);
    if(0 < n)
    {
        printf("read %d bytes:%s\n", n, buf);
    }

    /**
    * 主动发送FIN
    **/
    close(sockfd);

    return 0;

}

这里做的一个处理是:客户端在发送数据后,等待一段时间,等待服务端的FIN,使其服务端在四次挥手结束后进入到TIME_WAIT状态。

编译程序后,首先运行服务端,再运行客户端,此时一路tcp连接建立,并使得服务端进入到了TIME_WAIT的状态,在此时,再运行一次客户端程序,此时收到错误输出:Connection refused。

通过抓的包分析,可以看到,在第一路连接释放后,在服务端进入到TIME_WAIT状态时,第二路的客户端进行连接时,SYN对应的响应为RST,详细的包信息见下图:

tcpdump抓包

这个现象与之前碰到的问题现象是基本一致的,根据这个思路,尝试去分析了是否是服务端出现了某些异常的情况主动释放了tcp连接,因此在某段时间内(TIME_WAIT的时间一般为:2MSL),对于所有的客户端都无法连接上。由于其他事情,这个问题也暂时放了放,目前还未找到确切的原因。

结束语

在整个网络编程中,其实TIME_WAIT的状态是需要特别注意的。网络编程虽然坑多,但是只要我们结合原理一步步分析,整个过程都是其乐无穷的。(逃。。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值