socket编程(6)

本章主要任务;
1.继续晚上TCP回射客户/服务器程序
2.再次强调TCP是个流协议
3.僵死进程与SIGCHLD信号

一、TCP回射客户/服务器程序

 

 

第一种会粘包,第二种用在行位加\n。readline.

第三种解决粘包问题就是使用,定长包,但是这种方式效率低,浪费缓冲区。改进机制是我们可以在包中加入包长信息,之前讲过了。

 

二、TCP是个流协议

 

 

三、僵死进程与SIGCHLD信号

1.可以signal(SIGCHLD,SIG_IGN)忽略信号,来避免僵死进程
2.捕捉该信号来避免僵死进程 signal(SIGCHLD,handle_sigchld)
在handle_sigchld函数中使用wait函数。原型如下:
pid_t wait(int *status);
这里我们不关心退出状态 所以用 wati(NULL);

但是使用wait 有一个问题,就当有多个子进程都退出时,wait仅仅等待第一个子进程退出及返回了
这时候就用到 waitpid。函数原型如下:

pid_t waitpid(pid_t pid, int *status, int options);

在这之前,我们先模拟一下5个客户端连接服务器,并且同时退出的情况

我们对客户端程序进行一下更改,创建5个套接字。

 1 int main()
 2 {
 3     /*创建套接字*/    
 4     int sockfd[5];
 5     int i;
 6     for(i=0;i<5;i++)
 7     {
 8         if((sockfd[i] = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
 9             printf("socket err");
10 
11         /*serv addr and port*/    
12         struct sockaddr_in servaddr;
13         memset(&servaddr,0,sizeof(servaddr));
14         servaddr.sin_family = AF_INET;
15         servaddr.sin_port = htons(5188);
16         servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
17     
18     /*连接,一旦连接成功,sockfd套接字就处于已连接状态,从逻辑上
19       是与服务器端的conn套接字连接*/    
20         if(connect(sockfd[i],(struct sockaddr*)&servaddr,sizeof(servaddr)) <0)
21             printf("connect err");
22         struct sockaddr_in localaddr;
23         socklen_t addrlen = sizeof(localaddr);
24         if(getsockname(sockfd[i],(struct sockaddr*)&localaddr,&addrlen)<0)
25             ERR_EXIT("getsockname");
26         printf("ip=%s port=%d\n",inet_ntoa(localaddr.sin_addr),ntohs(localaddr.sin_port));    
27     }
28     echo_cli(sockfd[0]);
29 
30     return 0;
31 }

这里我们创建五个套接字与服务器相连,这里只让第一个套接字跟服务器端通信

 

 

启动服务器,启动客户端
这时候我们发现有五个客户端与服务器连接
如图:

现在讲客户端退出
我们发现出现了4个僵死进程。

如图

 

这时候我们可以用waitpid来解决
waitpid(-1,NULL,WNOHANG);

 

1 void handle_sigchld(int sig)
2 {
3     //wait(NULL);
4     while(waitpid(-1,NULL,WNOHANG) >0)
5         ;
6 
7 }

 

我们发现有时候是三个有时候是四个僵死进程。
这是因为5个子进程同时向父进程发送信号,父进程在处理第一个信号是,其他到达信号会被忽略。所以是不可靠信号。
这个跟FIN到达的时间有关。
那么我们能不能解决这个问题呢???其实很简单,我们用一个while循环来解决。这里是一个死循环
while(waitpid(-1,NULL,WNOHANG)>0)

大于0表示成功处理一个子进程,

那么循环退出的条件呢? 当没有子进程退出的时候,我们这边指定的是WNOHANG就是不挂起。没有子进程退出就会放回0就会退出死循环

通过这种方式,我们就完美的解决了僵死进程。我们推荐用waitpid,而不使用第一种signal(SIGCHLD,SIG_IGN的方式,因为我们可以处理更多的事情。

 

posted @ 2017-03-24 21:08  ren_zhg1992  阅读(185)  评论(0)    收藏  举报