Linux network programming Wait () and waitpid () explanation

Source: Internet
Author: User
Tags socket error terminates htons

This article is about the difference and connection between wait and Waitpid. To avoid the creation of a zombie process, whenever we create a subprocess, the master process waits for the child process to return to clean up the subprocess.  To do this, we add the SIGCHLD signal processing function to the server program. After the client disconnects, there is a large number of zombie processes on the server side. This is because after the server child process terminates, the SIGCHLD signal is sent to the parent process, and the parent process ignores the signal by default. To avoid the creation of a zombie process, whenever we create a subprocess, the master process waits for the child process to return to clean up the subprocess. To do this, we add the SIGCHLD signal processing function to the server program.

#include <stdlib.h>#include<stdio.h>#include<errno.h>#include<string.h>#include<unistd.h>#include<sys/socket.h>#include<netinet/inch.h>#include<sys/types.h>#include<netdb.h>#defineServ_port 1113#defineListenq 32#defineMAXLINE 1024/** * Connection handler function * **/voidStr_echo (intFD);voidSIG_CHLD (intSigno) {pid_t pid;intStat;pid= Wait (&stat);//gets the child process process numberprintf"Child %d terminated\n", PID);return;}intMain (intargcChar*argv[]) {intlistenfd,connfd;pid_t childpid;socklen_t Clilen;structsockaddr_in servaddr;structsockaddr_in cliaddr;//struct sockaddr_in servaddr;//struct sockaddr_in cliaddr;if(LISTENFD = socket (af_inet, Sock_stream,0))==-1) {fprintf (stderr,"Socket error:%s\n\a", Strerror (errno)); Exit (1);}/*server-side fill SOCKADDR structure*/bzero (&AMP;SERVADDR,sizeof(SERVADDR)); servaddr.sin_family=af_inet;servaddr.sin_addr.s_addr=htonl (inaddr_any); Servaddr.sin_port=htons (serv_port); signal (SIGCHLD,SIG_CHLD);//Handling SIGCHLD Signals/*Bundle LISTENFD Descriptors*/ if(Bind (LISTENFD, (structsockaddr*) (&AMP;SERVADDR),sizeof(structSOCKADDR)) ==-1) {fprintf (stderr,"Bind error:%s\n\a", Strerror (errno)); Exit (1);}/*Monitoring LISTENFD descriptors*/if(Listen (LISTENFD,5)==-1) {fprintf (stderr,"Listen error:%s\n\a", Strerror (errno)); Exit (1);} for ( ; ; ) {Clilen=sizeof(CLIADDR);/*server blocked until client program establishes a connection*/if(Connfd=accept (LISTENFD, (structsockaddr*) (&AMP;CLIADDR), &clilen) <0){/*When a child process terminates, the execution of the signal processing function sig_chld, and when the function returns, the Accept system call may return a eintr error, some kernels will automatically restart the interrupted system calls, for portability, will consider the processing of eintr*/if(errno==eintr)Continue; fprintf (stderr,"Accept error:%s\n\a", Strerror (errno)); Exit (1);}//after a client has established a connectionif((Childpid = fork ()) = =0) {/*Child Process*/Close (LISTENFD);/*turn off the listener socket*/Str_echo (CONNFD);/*processing requests for this client*/Exit (0);} Close (CONNFD);/*parent process closes connection socket, continues waiting for other connections to arrive*/}}voidStr_echo (intsockfd) {ssize_t n;CharBuf[maxline];again: while((n = Read (SOCKFD, buf, MAXLINE)) >0) Write (SOCKFD, buf, n);if(N <0&& errno = = eintr)//be interrupted, re-enterGotoagain;Else if(N <0){//Errorfprintf (stderr,"Read Error:%s\n\a", Strerror (errno)); Exit (1);} After the code is modified, when the client disconnects, the server-side parent process receives the SIGCHLD signal from the child process, executes the SIG_CHLD function, cleans up the child process, and no more zombie processes are present. At this point, after a client actively disconnects, the server side outputs a message similar to the following: child12306terminatedwait and Waitpid the SIG_CHLD function in the above program, we used Wait () to clear the terminating subprocess. There is also a similar function, Wait_pid. Let's take a look at these two function prototypes: pid_t Wait (int*status);p id_t waitpid (pid_t pid,int*status,intoptions); Official description: All of these system calls is used to wait forState changesinchA child of the calling process, and obtain information the "the child" whose state has changed. A State Change isConsidered to be:the child ter minated; The child is stopped by a signal;  Or the child is resumed by a signal. In the CaseOf a terminated child, performing a wait allows the system to release the resources associated with the child;ifA wait isNot performed, then the terminated child remainsinchA"Zombie"State (see NOTES below). The difference and connection between wait and waitpid: The Wait () system call suspends execution of the calling process Unti  L One of its children terminates. The call Wait (&status) isequivalent To:waitpid (-1, &status,0); The Waitpid () system call suspends execution of the calling process until a child specified by PID argument have change  D state. bydefault, Waitpid () waits only forTerminated children, but ThisBehavior isModifiable via the options argument, asdescribed below. That is, the wait () system call suspends the calling process until any one of its child processes terminates. Call Wait (&status) has the effect of calling Waitpid (-1, &status,0) is the same as the effect. Waitpid () suspends the calling process until the process state specified by the parameter PID changes, by default, Waitpid () waits only on the child process's terminating state. If necessary, you can handle the non-terminating state by setting the options value. For example: The value of options isAn or of zero OR more of the following Constants:wnohangreturnImmediatelyifNo child has exited. Wuntraced alsoreturn  ifA child had stopped (but not traced via Ptrace (2)). Status forTraced children which have stopped isProvided evenif  ThisOption isNot specified. Wcontinued (since Linux2.6.Ten) Alsoreturn ifa stopped child had been resumed by delivery of Sigcont. Wait a second. Non-terminating status. Now let's look at the difference between wait () and waitpid () by example. By modifying the client program, 5 sockets are established in the client program to connect to the server at once, as shown in the following code:

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <netdb.h>
#define Serv_port 1113
#define MAXLINE 1024
void Str_cli (FILE *fp, int sockfd);
Int
Main (int argc, char **argv)
{
int i,sockfd[5];
struct sockaddr_in servaddr;
if (argc! = 2) {
fprintf (stderr, "Usage:tcpcli <ipaddress>\n\a");
Exit (0);
}
for (i=0;i<5;++i) {//Five connections to the server to allow the server to create 5 sub-processes
if ((Sockfd[i]=socket (af_inet,sock_stream,0)) ==-1) {
fprintf (stderr, "Socket error:%s\n\a", Strerror (errno));
Exit (1);
}

/* Client program fills the data on the server */
Bzero (&servaddr,sizeof (SERVADDR));
Servaddr.sin_family=af_inet;
Servaddr.sin_port=htons (Serv_port);
if (Inet_pton (Af_inet, argv[1], &servaddr.sin_addr) <= 0) {
fprintf (stderr, "Inet_pton error:%s\a\n", Strerror (errno));
Exit (1);
}
/* Client Initiates connection request */
if (Connect (sockfd[i), (struct sockaddr *) (&AMP;SERVADDR), sizeof (struct sockaddr)) ==-1) {
fprintf (stderr, "Connect error:%s\a\n", Strerror (errno));
Exit (1);
}
}
STR_CLI (stdin, sockfd[0]);/* interacts with the server only with the first socket */
Exit (0);
}
void
STR_CLI (FILE *fp, int sockfd)
{
int nbytes=0;
Char Sendline[maxline],recvline[maxline];
while (Fgets (Sendline, MAXLINE, fp)! = NULL) {//reads a row from standard input
Write (SOCKFD, Sendline, strlen (sendline));//Send the line to the server
if ((Nbytes=read (SOCKFD, Recvline, MAXLINE)) = = 0) {//Read data from the server from the SOCKFD
fprintf (stderr, "Str_cli:server terminated prematurely\n");
Exit (1);
}
recvline[nbytes]= ' + ';
Fputs (Recvline, stdout);
}
}

When the customer terminates, so that the open descriptors are automatically closed by the kernel, so 5 connections basically at the same time, the equivalent of 5 fin sent to the server, which will cause 5 server sub-processes basically at the same time, resulting in 5 SIGCHLD signals are delivered to the server parent process almost simultaneously. As shown below:

That is, almost at the same time, 5 SIGCHLD signals are delivered to the parent process, which in turn will cause the zombie process to appear. Because UNIX generally does not queue the signal, which resulted in 5 SIGCHLD submitted, only one sig_chld function, the remaining four sub-processes became the zombie process. In this case, the correct approach is to call Waitpid () instead of wait ().
Therefore, the signal processing function in our final server-side code makes a small change to the following:
The code is as follows: void
SIG_CHLD (int signo)
{
pid_t pid;
int stat;
while (PID = Waitpid ( -1, &stat, Wnohang)) > 0)
printf ("Child%d terminated\n", PID);
Return
}

So far, we've solved three types of scenarios that you might encounter in network programming:
1. When a child process is derived, the SIGCHLD signal must be captured. Code snippet: Signal (SIGCHLD,SIG_CHLD);
2. When the signal is captured, the interrupted system call must be processed. Code snippet: if (ERRNO==EINTR) continue;
3.SIGCHLD signal processing functions must be written correctly in case a zombie process occurs. Code snippet: while (PID = Waitpid ( -1, &stat, Wnohang)) > 0)
Http://www.jb51.net/LINUXjishu/113671.html

Linux network programming Wait () and waitpid () explanation

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.