SOCKET CLOSE_WAIT FIN_WAIT2 TIME_WAIT重现测试

 1 #include <iostream>
 2 #include <sys/types.h>
 3 #include <sys/socket.h>
 4 #include <netinet/in.h>
 5 #include <arpa/inet.h>
 6 
 7 #include <unistd.h>
 8 #include <errno.h>
 9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 
13 bool server(char *ip,int port){
14     int socketfd = 0;
15     if(-1 ==(socketfd = socket(AF_INET,SOCK_STREAM,0))){
16         printf("create socket faile,errno:%d\n",errno);
17         return false;
18     }
19     sockaddr_in serverAddr;
20     memset(&serverAddr,0,sizeof(serverAddr));
21     serverAddr.sin_family = AF_INET;
22     serverAddr.sin_port = htons(port);
23     serverAddr.sin_addr.s_addr = inet_addr(ip);
24     if(-1==bind(socketfd,(struct sockaddr *)&serverAddr,sizeof(serverAddr))){
25         printf("bind socket fail,errno:%d\n",errno);
26         return false;
27     }
28     if(-1==listen(socketfd,10)){
29         printf("listen socket fail,errno:%d\n",errno);
30         return false;
31     }
32     printf("server has started...\n");
33     int confd = 0;
34     sockaddr_in clientAddr;
35     memset(&clientAddr,0,sizeof(clientAddr));
36     int sockLen = 0;
37     if(-1==(confd = accept(socketfd,(struct sockaddr *)&clientAddr,(socklen_t*)&sockLen))){
38         printf("accept socket fail,errno:%d\n",errno);
39         return false;
40     }
41     int len = 0;
42     while(1){
43         char recvBuf[64]={0};
44         len = recv(confd,recvBuf,sizeof(recvBuf),0);
45         printf("len:%d,str:%s\n",len,recvBuf);
46         if(len ==0){
47             printf("client shutdown socket...\n");
48             break;
49         }
50     }
51     while(1){
52         sleep(3);
53     }
54     return true;
55 }
56 bool client(char *ip,int port){
57     int socketfd = 0;
58     if(-1 == (socketfd = socket(AF_INET,SOCK_STREAM,0))){
59         printf("create socket fail,errno:%d\n",errno);
60         return false;
61     }
62     sockaddr_in serverAddr;
63     memset(&serverAddr,0,sizeof(serverAddr));
64     serverAddr.sin_family = AF_INET;
65     serverAddr.sin_port = htons(port);
66     serverAddr.sin_addr.s_addr = inet_addr(ip);
67 
68     if(-1==connect(socketfd,(struct sockaddr*)&serverAddr,sizeof(serverAddr))){
69         printf("connect socket fail,errno:%d\n",errno);
70         return false;
71     }
72     char * sendBuf = "hello server";
73     send(socketfd,sendBuf,strlen(sendBuf)+1,0)
74     while(1){
75         sleep(3);
76     }
77     return true;
78 }
79 int main(int argc, char *argv[])
80 {
81     if(argc!=4){
82         printf("usage:CloseWaitTest [0|1] ip port. 0:server,1:client\n");
83         return 1;
84     }
85     if(atoi(argv[1])==0){
86         server(argv[2],atoi(argv[3]));
87     }
88     if(atoi(argv[1])==1){
89         client(argv[2],atoi(argv[3]));
90     }
91     return 0;
92 }

 

测试1:进程退出的方式关闭连接。正常关闭客户端进程,服务端会收到来自于客户端的关闭请求,服务器端的连接套接字状态进入CLOSE_WAIT,由于服务器端没有主动发送关闭请求,所以客户端的套接字状态处于FIN_WAIT2

正常运行截图

服务器端的监听套接字处于LISTEN状态,服务器和客户端直接的连接套接字处于ESTABLISHED状态

ctrl+c将客户端退出

服务器端套接字处于CLOSE_WAIT状态,客户端进程套接字处于FIN_WAIT2状态,FIN_WAIT2超时后系统会回收该套接字资源,超时时间系统默认为60秒,可以通过通过 /sbin/sysctl -a | grep fin_timeout查看

由于服务器端一直没有主动关闭所以一直处于CLOSE_WAIT状态

 

测试2:在client函数中添加shutdown,主动关闭连接,测试结果与测试1相同

在73行与74行之间添加:

shutdown(socketfd,SHUT_WR)

 

测试结果与测试1相同

 

测试3:结合测试2,服务端收到关闭后,再发送数据给客户端,然后shutdown

在50行与51行之间添加:

    char * sendBuf = "hello client";
    send(confd,sendBuf,strlen(sendBuf)+1,0);
    sleep(10);
    shutdown(confd,SHUT_WR);

客户端到服务端套接字状态为TIME_WAIT,持续一分钟

 

close和shutdown比较

客户端调用shutdown(fd,SHUT_RDWR)时直接关闭连接,在继续接收数据时得到104异常:connection reset by peer

客户端调用close(fd)时,是减少描述符的引用计数,当计数为0时,释放描述符,而不是关闭连接,再继续接收数据时得到9异常:EBADF,无效的文件描述符

 

状态图

 

posted @ 2018-01-20 09:56  DoSomethingYouLike  阅读(449)  评论(0编辑  收藏  举报