Okay, today is the second chapter of our Linux Server model-tcp pre-derived subprocess service, accept no lockout protection.
The literal understanding is that a certain number of sub-processes are derived at the start-up stage, and these sub-processes can serve them immediately when each client connection arrives. Note Unlike our first article, our first article is to derive a child process for each customer, one for each, and one for the other. It is also worth noting that if at some point the number of customers is exactly equal to the pre-derived subprocess, then for the next customer, it is still possible to perform a three-time handshake to connect, only to wait until at least one child process is available.
In addition, our server business is the same as the first article, is based on the instructions sent by the client to return the corresponding data.
Okay, come and see our code:
SERV.C:
#include "pub.h"Static intNchildren;Staticpid_t *pids;voidSig_int (intSigno);intMainintargcChar**ARGV) {intLISTENFD;structSockaddr_in servaddr;intOn =1;inti =0; pid_t Child_make (int,int);if(ARGC! =3) {fprintf(stderr,"Usage:serv <port> <nchildren>\n");//Specify the number of ports and pre-derived child processes here Exit(-1); }if(LISTENFD = socket (af_inet, Sock_stream,0)) <0) {perror ("Serv socket error");Exit(-1); } servaddr.sin_family = Af_inet; Servaddr.sin_port = htons (Atoi (argv[1])); SERVADDR.SIN_ADDR.S_ADDR = htonl (Inaddr_any);//SET REUSABLESetSockOpt (LISTENFD, Sol_socket, SO_REUSEADDR, &on,sizeof(on));if(Bind (LISTENFD, (structSOCKADDR *) &servaddr,sizeof(SERVADDR)) <0) {perror ("Serv bind error");Exit(-1); }if(Listen (LISTENFD, Listenq) <0) {perror ("Serv Listen error");Exit(-1); } Nchildren = Atoi (argv[2]); PIDs =calloc(Nchildren,sizeof(pid_t)); for(i =0; i < Nchildren; i++) Pids[i] = Child_make (i, LISTENFD); Signal (SIGINT, sig_int); for( ; ; )//parent just pausePause ();//everything done by children Exit(0);}voidSig_int (intSigno) {inti =0; for(i =0; i < Nchildren; i++) {Kill (Pids[i], SIGTERM); } while(Wait (NULL) >0);//wait for all children //For wait //If the calling parent process does not have a child process then return-1, and set errno if(errno! = echild) {Perror ("Sig_int Error");Exit(-1); }Exit(0);}
Follow here:
for0;i < nchildren; i++) pids[i] = child_make(i ,listenfd);Signal(SIGINT, sig_int);for( ; ; ) //parent just pause pause(); //everything done by children
The nchildren here are extracted from our parameters, representing the number of pre-derived child processes. For PIDs arrays, the Child_make () function is used to derive the child process, while the PID of the child process is returned to an item in the PIDs array. The PIDs here is our dynamically allocated array, which is used to store the PID of each of our sub-processes. The Child_make () function here is used to derive the child process, including the processed code. Bring us to explain it.
Look at the back of the signal (SIGINT, sig_int); Is the processing function that registers the SIGINT signal. We will kill all the derived sub-processes after we receive the SIGINT signal.
This is with the later for Loop and the pause () function just to let the parent process hang. Let all of the processing be referred to a pre-derived child process.
Look at our sig_int () Signal processing function:
void sig_int (int signo) { int i = 0 ; for (i = 0 ; i < Nchildren; i++) {kill (Pids[i], SIGTERM); } while (wait (NULL) > 0 ); //wait for all children//for wait //If the calling parent process does not have a child process then return-< Span class= "Hljs-number" >1 , and set errno if (errno! = echild) {perror ( "Sig_int error" ); exit (- 1 ); } exit ( 0 );}
At a glance, that's what we said earlier, kill all derived child processes. Through while (Wait (NULL) > 0), reclaim all the resources of the Forbidden City. Note that in our comments: For wait, if the calling parent process does not have a child process, it returns-1 and sets errno. This errno is echild. This is not a mistake.
Okay, next is the real function that derives the child process.
To see the Child_make () function:
#include "pub.h"pid_t child_make(intint listenfd){ pid_t pid; void child_main(intint); if0)//parent just return pid of child return pid; //child child_main(i ,listenfd); //nerver return}
Also very concise, fork return if is greater than 0, is the child process PID, return can. Let's leave the PIDs array saved above. In the case of a subprocess, enter the Child_main () function, which is the function we are actually connecting to the client.
Take a look at the Child_main () function:
#include "pub.h"voidChild_main (intIintLISTENFD) {intCONNFD;voidChild_handle (int,int);structSockaddr_in cliaddr; Socklen_t Len;Char*buff; for( ; ; ) {len =sizeof(CLIADDR);if(CONNFD = Accept (LISTENFD, (structSOCKADDR *) &cliaddr, &len) <0){if(errno = = eintr) {Continue; }Else{Perror ("The num%d Child_main accept error");Continue; }} buff = Inet_ntoa (cliaddr.sin_addr);fprintf(STDOUT,"%s has been handled\n", buff); Fflush (stdout); Child_handle (i, CONNFD);fprintf(STDOUT,"%s has left\n", buff); Fflush (stdout); Close (CONNFD); } close (LISTENFD);}
It's not very difficult, just like the connection in our first article. Through a For loop, waiting for the accept to return, once returned and error-free, first print A has been handled, into the Child_handle () function, this is our business code function to deal with the child process, and later.
Whenever a subprocess finishes processing a business, it promises to have a left and closes the CONNFD, noting that our loop does not quit and is always on standby.
And look at our Child_handle () function:
#include "pub.h"voidChild_handle (intIintSOCKFD) {CharBuff[maxline];intN time_t MyTime; for( ; ; ) {if((n = read (SOCKFD, buff, MAXLINE)) <=0){if(N <0&& errno = = eintr)Continue;Else if(n = =0){//Disconnect, to Child_main processing Break; }Else{Perror ("Child num%d child_handle read error"); Break; } }//Compare the first few strings, is not Gettime, is the return time, otherwise return Gettime Command Error if((strncmp(Buff,"GETTIME",7) ==0) || (strncmp(Buff,"GetTime",7) ==0) {MyTime = time (NULL);snprintf(Buff,sizeof(Buff),'%s ', CTime (&mytime)); Writen (SOCKFD, Buff,strlen(buff));//It's best to use writen (custom)}Else{//If not, return to Gettime Command Error snprintf(Buff,sizeof(Buff),"Gettime Command Error"); Writen (SOCKFD, Buff,strlen(buff)); } }}
This business code is basically the same as the Do_child () function of our first article. Compares the first few strings, is not Gettime or Gettime, is the return time, otherwise returns Gettime Command Error.
Which also contains the writen function, I put it out, is the first article in the Writen function, will not explain;
#include "pub.h"intWriten (intSOCKFD,Const Char*buff,intN) {intNleft = n;intNcount =0;Const Char*ptr = buff; while(Nleft >0) {if((ncount = write (SOCKFD, PTR, nleft)) <=0) {if(errno = = eintr) ncount =0;//call again Else return-1; } nleft-= ncount; PTR + = ncount; }returnN-nleft;}
In addition, there is our signal processing function signal () function, I also post it.
/ * include signal * /#include "pub.h"Sigfunc *Signal(intSigno, Sigfunc *func) {structSigaction Act, oact; Act.sa_handler = func; Sigemptyset (&act.sa_mask); Act.sa_flags =0; if (Signo = = SIGALRM) {#ifdef Sa_interruptAct.sa_flags |= Sa_interrupt;/ * SunOS 4.x * /#endif}Else{#ifdef Sa_restartAct.sa_flags |= Sa_restart;/ * SVR4, 44BSD * /#endif} if (Sigaction (Signo, &act, &oact) <0)return(Sig_err);return(Oact.sa_handler);}/ * END signal * /Sigfunc *signal (intSigno, Sigfunc *func)/* for our signal () function */{Sigfunc *sigfunc; if (Sigfunc =Signal(Signo, Func)) = = Sig_err) {perror ("Signal Error"); Exit1); }return(Sigfunc);}
This is a picture of our server model today, note that each of our sub-processes have LISTENFD, each child process through this listenfd to accept, to get a client connection. At the same time, this LISTENFD descriptor is just a subscript for the file structure. There are currently so many reference counts.
Okay, this is our Linux server model for today. The second article –tcp pre-derived subprocess service, accept no lockout protection. Do you get it?
TCP pre-derived Subprocess service program, accept no lockout protection