码迷,mamicode.com
首页 > 其他好文 > 详细

7.1 TCP IP的11种状态

时间:2018-08-01 19:36:41      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:error   sea   pid   bsp   main   nis   工程   http   super   

  在研究TCP IP的11种状态之前,我们先看一下服务器中存在僵尸进程的情况。

服务器是多进程模型,客户端是单进程。

服务器程序如下:

  1 #include <sys/types.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <stdio.h>
  5 #include <string.h>
  6 #include <errno.h>
  7 #include <arpa/inet.h>
  8 #include <sys/socket.h>
  9 #include <netinet/in.h>
 10 #include <sys/socket.h>
 11 #include <netinet/ip.h> /* superset of previous */
 12 
 13 
 14 int main()
 15 {
 16     int sockfd = 0;
 17     sockfd = socket(AF_INET, SOCK_STREAM, 0);
 18     
 19     if(sockfd == -1)
 20     {
 21         perror("socket error");
 22         exit(0);
 23     }
 24     
 25     struct sockaddr_in addr;
 26     addr.sin_family = AF_INET;
 27     addr.sin_port = htons(8001);
 28     inet_aton("192.168.31.128", &addr.sin_addr);
 29     //addr.sin_addr.s_addr = inet_addr("192.168.6.249");
 30     //addr.sin_addr.s_addr = INADDR_ANY;
 31     
 32     int optval = 1;
 33     if( setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)
 34     {
 35         perror("setsockopt error");
 36         exit(0);    
 37     }
 38     
 39     if( bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
 40     {
 41         perror("bind error");
 42         exit(0);
 43     }
 44     
 45     if(listen(sockfd, SOMAXCONN) < 0)
 46     {
 47         perror("listen error");
 48         exit(0);
 49     }
 50     
 51     struct sockaddr_in peeraddr;
 52     socklen_t peerlen;
 53     
 54     int conn = 0;
 55     
 56     while(1)
 57     {
 58         conn = accept(sockfd, (struct sockaddr *)&peeraddr, &peerlen);
 59         if(conn == -1)
 60         {
 61             perror("accept error");
 62             exit(0);
 63         }
 64         
 65         char *p = NULL;
 66         int peerport = 0;
 67         p = inet_ntoa(peeraddr.sin_addr);
 68         peerport = ntohs(peeraddr.sin_port);
 69         printf("peeraddr = %s\n peerport = %d\n", p, peerport);
 70         
 71         pid_t pid = fork();
 72         
 73         if(pid == -1)
 74         {
 75             perror("fork error");
 76             exit(0);
 77         }
 78         
 79         if(pid == 0)
 80         {
 81             char recvbuf[1024] = {0};
 82             int ret = 0;
 83             while(1)
 84             {
 85                 ret = read(conn, recvbuf, sizeof(recvbuf));
 86         
 87                 if(ret == 0)
 88                 {
 89                     printf("peer closed \n");
 90                     exit(0);
 91                 }
 92                 else if(ret < 0)
 93                 {
 94                     perror("read error");
 95                     exit(0);
 96                 }
 97         
 98                 fputs(recvbuf, stdout);
 99         
100                 write(conn, recvbuf, ret);
101             }    
102         }
103     }
104     
105     close(conn);
106     close(sockfd);
107     
108     return 0;
109 }

客户端程序如下:

 1 #include <sys/types.h>
 2 #include <unistd.h>
 3 #include <stdlib.h>
 4 #include <stdio.h>
 5 #include <string.h>
 6 #include <errno.h>
 7 #include <arpa/inet.h>
 8 #include <sys/socket.h>
 9 #include <netinet/in.h>
10 #include <sys/socket.h>
11 #include <netinet/ip.h> /* superset of previous */
12 
13 int main()
14 {
15     int sockfd = 0;
16     sockfd = socket(AF_INET, SOCK_STREAM, 0);
17     
18     struct sockaddr_in addr;
19     addr.sin_family = AF_INET;
20     addr.sin_port = htons(8001);
21     inet_aton("192.168.31.128", &addr.sin_addr);
22     //addr.sin_addr.s_addr = inet_addr("192.168.31.128");
23     
24     if( connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 )
25     {
26         perror("connect error");
27         exit(0);
28     }
29     
30     char recvbuf[1024] = {0};
31     char sendbuf[1024] = {0};
32     int ret = 0;
33     
34     while(fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
35     {
36         write(sockfd, sendbuf, strlen(sendbuf));
37         
38         ret = read(sockfd, recvbuf, sizeof(recvbuf));
39         
40         fputs(recvbuf, stdout);
41         memset(recvbuf, 0, sizeof(recvbuf));
42         memset(sendbuf, 0, sizeof(sendbuf));
43 
44     }
45     
46     close(sockfd);
47     
48     return 0;
49 }

执行结果如下:

技术分享图片

 

可以看到,当客户端使用ctrl+c关闭时,服务器中的子进程成了僵尸进程。这是因为,子进程死了,但是没有进程给它收尸,我们可以调用signal(SIGCHLD, SIG_IGN)函数告诉内核,忽略SIGCHLD信号,让内核来处理SIGCHLD信号,也即让内核收尸,但是工程中一般不这样做。一般是注册信号让父进程调用wait来收尸。

修改服务器程序,加入信号处理函数,如下所示:

 

  1 #include <sys/types.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <stdio.h>
  5 #include <string.h>
  6 #include <errno.h>
  7 #include <signal.h>
  8 #include <arpa/inet.h>
  9 #include <sys/socket.h>
 10 #include <netinet/in.h>
 11 #include <sys/socket.h>
 12 #include <netinet/ip.h> /* superset of previous */
 13 
 14 void handler(int num)
 15 {
 16     printf("child die\n");
 17     wait(NULL);
 18 }
 19 
 20 int main()
 21 {
 22     int sockfd = 0;
 23     signal(SIGCHLD, handler);
 24     sockfd = socket(AF_INET, SOCK_STREAM, 0);
 25     
 26     if(sockfd == -1)
 27     {
 28         perror("socket error");
 29         exit(0);
 30     }
 31     
 32     struct sockaddr_in addr;
 33     addr.sin_family = AF_INET;
 34     addr.sin_port = htons(8001);
 35     inet_aton("192.168.31.128", &addr.sin_addr);
 36     //addr.sin_addr.s_addr = inet_addr("192.168.6.249");
 37     //addr.sin_addr.s_addr = INADDR_ANY;
 38     
 39     int optval = 1;
 40     if( setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)
 41     {
 42         perror("setsockopt error");
 43         exit(0);    
 44     }
 45     
 46     if( bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
 47     {
 48         perror("bind error");
 49         exit(0);
 50     }
 51     
 52     if(listen(sockfd, SOMAXCONN) < 0)
 53     {
 54         perror("listen error");
 55         exit(0);
 56     }
 57     
 58     struct sockaddr_in peeraddr;
 59     socklen_t peerlen;
 60     
 61     int conn = 0;
 62     
 63     while(1)
 64     {
 65         conn = accept(sockfd, (struct sockaddr *)&peeraddr, &peerlen);
 66         if(conn == -1)
 67         {
 68             perror("accept error");
 69             exit(0);
 70         }
 71         
 72         char *p = NULL;
 73         int peerport = 0;
 74         p = inet_ntoa(peeraddr.sin_addr);
 75         peerport = ntohs(peeraddr.sin_port);
 76         printf("peeraddr = %s\n peerport = %d\n", p, peerport);
 77         
 78         pid_t pid = fork();
 79         
 80         if(pid == -1)
 81         {
 82             perror("fork error");
 83             exit(0);
 84         }
 85         
 86         if(pid == 0)
 87         {
 88             char recvbuf[1024] = {0};
 89             int ret = 0;
 90             while(1)
 91             {
 92                 ret = read(conn, recvbuf, sizeof(recvbuf));
 93         
 94                 if(ret == 0)
 95                 {
 96                     printf("peer closed \n");
 97                     exit(0);
 98                 }
 99                 else if(ret < 0)
100                 {
101                     perror("read error");
102                     exit(0);
103                 }
104         
105                 fputs(recvbuf, stdout);
106         
107                 write(conn, recvbuf, ret);
108             }    
109         }
110     }
111     
112     close(conn);
113     close(sockfd);
114     
115     return 0;
116 }

 

执行结果如下:

技术分享图片

 

由上图可以看到服务器中子进程死掉后,不存在僵尸进程。而且服务器还正常工作,我们重启客户端,依然可以正常发送数据。

 

7.1 TCP IP的11种状态

标签:error   sea   pid   bsp   main   nis   工程   http   super   

原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9403359.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!