Multi-process service framework in Linux

Source: Internet
Author: User

Tip: Change the token from tinyproxy and pay tribute to the original author!

At the beginning of a program, you can define the following constants:

# Define maxservices128/* Maximum number of service calls for each process to prevent installation errors */

# Define startservers32/* Initial dynamic service progress */

# Define maxspareservers32/* Maximum number of air service processes */

# Define minspareservers8/* Minimum number of empty queue service processes */

The user only needs to modify the handle_connection function at the bottom of the program, and check the handling problem that the customer requests, information Processing and progress group control are completed by the framework. The kernel passed through in rhes 3 2.4kernel and Debian etch 2.6kernel.

Welcome to correction.

# Include <stdio. h>

# Include <stdlib. h>

# Include <string. h>

# Include <assert. h>

# Include <unistd. h>

# Include <errno. h>

# Include <signal. h>

# Include <sys/types. h>

# Include <sys/Mman. h>

# Include <sys/file. h>

# Include <sys/Wait. H>

# Include <sys/socket. h>

# Include <ARPA/inet. h>



/*

* Forrija changed his role from tinyproxy.

*/



# Define maxlisten1024/* maximum listener number, which is used for the listen function */

# Define maxclients64/* Maximum Service progress */

# Define maxservices128/* the maximum number of service calls for each process. The progress group is updated on a regular basis to prevent installation errors */

# Define startservers32/* Initial dynamic service progress */

# Define maxspareservers32/* Maximum number of air service processes */

# Define minspareservers8/* Minimum number of empty queue service processes */



# Define Port 8000/* listener port ready */



/* Global Change zone */

Int listenfd;/* service socket */

Int received_sighup = 0;/* receive the HUP token */

Int quit = 0;/* exit the tag */



# Define server_count_lock () _ child_lock_wait ()

# Define server_count_unlock () _ child_lock_release ()



/* Shared variable volume */

Static struct flock lock_it, unlock_it;

Static int lock_fd =-1;



Enum child_status_t {t_empty, t_waiting, t_connected };



Struct child_s {

Pid_t tid;

Unsigned int connects;

Enum child_status_t status;

};



/*

* Sub-Progress data group-in the shared memory area

*/

Static struct child_s * child_ptr;



/*

* The number of service progress that is waiting to be received by the consumer

*/

Static unsigned int * servers_waiting;



/*

* Allocate a shard of shared memory.

*/

Static void *

Malloc_shared_memory (size_t size)

{

Int FD;

Void * PTR;

Char buffer [32];



Static char * shared_file = "/tmp/MPS. Shared. xxxxxx ";



Assert (size> 0 );



Strncpy (buffer, shared_file, sizeof (buffer ));



If (FD = mkstemp (buffer) =-1)

Return (void *) map_failed;

Unlink (buffer );



If (ftruncate (FD, size) =-1)

Return (void *) map_failed;

PTR = MMAP (null, size, prot_read | prot_write, map_shared, FD, 0 );



Return PTR;

}



/*

* Allocate a shard of shared memory and clear the value 0.

*/

Static void *

Calloc_shared_memory (size_t nmemb, size_t size)

{

Void * PTR;

Long length;



Assert (nmemb> 0 );

Assert (size> 0 );



Length = nmemb * size;



PTR = malloc_shared_memory (length );

If (PTR = map_failed)

Return PTR;



Memset (PTR, 0, length );



Return PTR;

}



Static void

_ Child_lock_init (void)

{

Char lock_file [] = "/tmp/MPS. servers. Lock. xxxxxx ";



Lock_fd = mkstemp (lock_file );

Unlink (lock_file );



Lock_it.l_type = f_wrlck;

Lock_it.l_whence = seek_set;

Lock_it.l_start = 0;

Lock_it.l_len = 0;



Unlock_it.l_type = f_unlck;

Unlock_it.l_whence = seek_set;

Unlock_it.l_start = 0;

Unlock_it.l_len = 0;

}



Static void

_ Child_lock_wait (void)

{

Int RC;



While (rc = fcntl (lock_fd, f_setlkw, & lock_it) <0 ){

If (errno = eintr)

Continue;

Else

Return;

}

}



Static void

_ Child_lock_release (void)

{

If (fcntl (lock_fd, f_setlkw, & unlock_it) <0)

Return;

}



# Define server_inc () do {/

Server_count_lock ();/

++ (* Servers_waiting );/

Server_count_unlock ();/

} While (0)



# Define server_dec () do {/

Server_count_lock ();/

Assert (* servers_waiting> 0 );/

-- (* Servers_waiting );/

Server_count_unlock ();/

} While (0)



/*

* Configure the listener socket

*/

Static void

Start_listen_socket (unsigned short port)

{

Int sockfd;

Int on = 1;

Struct sockaddr_in ADDR;


Sockfd = socket (af_inet, sock_stream, 0 );

Setsockopt (sockfd, sol_socket, so_reuseaddr, & on, sizeof (on ));


Memset (& ADDR, 0, sizeof (ADDR ));

ADDR. sin_family = af_inet;

ADDR. sin_port = htons (port );

/*

* You need to specify the actual region address.

*/

ADDR. sin_addr.s_addr = inet_addr ("0.0.0.0 ");


If (BIND (sockfd, (struct sockaddr *) & ADDR, sizeof (ADDR) <0 ){

Fprintf (stderr, "unable to bind listening socket because of % s/n ",

Strerror (errno ));

Exit (-1 );

}


If (Listen (sockfd, maxlisten) <0 ){

Fprintf (stderr, "unable to start listening socket because of % s/n ",

Strerror (errno ));

Exit (-1 );

}


Listenfd = sockfd;

}



Void

Close_listen_socket (void)

{

Close (listenfd );

}



/*

* In this function, the handling handler for customer requests is listed below.

* When the processing is completed and the function is exited, The connfd is involved.

*/

Void

Handle_connection (INT connfd );



/*

* Sub-Progress main cycle

*/

Static void

Child_main (struct child_s * PTR)

{

Int connfd;

Struct sockaddr * cliaddr;

Socklen_t clilen;


Clilen = sizeof (struct sockaddr );

Cliaddr = (struct sockaddr *) malloc (clilen );

If (! Cliaddr ){

Fprintf (stderr,

"Cocould not allocate memory for Child address .");

Exit (0 );

}



PTR-> connects = 0;



While (! Quit ){

PTR-> Status = t_waiting;



Connfd = accept (listenfd, cliaddr, & clilen );



/*

* No licenses have been issued.

*/

If (connfd <0 ){

Fprintf (stderr,

"Accept returned an error (% s)... retrying .",

Strerror (errno ));

Continue;

}



PTR-> Status = t_connected;



Server_dec ();



Handle_connection (connfd );

PTR-> connects ++;



If (PTR-> connects = maxservices ){

Fprintf (stderr,

"Child has reached maxrequestsperchild (% u). Killing child./N ",

PTR-> connects );

Break;

}



Server_count_lock ();

If (* servers_waiting> maxspareservers ){

/*

* There are too many blank workflow service processes to exit.

*/

Fprintf (stderr,

"Waiting servers (% d) exceeds maxspareservers (% d). Killing child./N ",

* Servers_waiting, maxspareservers );

Server_count_unlock ();



Break;

} Else {

Server_count_unlock ();

}



Server_inc ();

}



PTR-> Status = t_empty;



Free (cliaddr );

Exit (0 );

}



/*

* Fork a sub-progress and calls the child_main () function (the Sub-Progress main cycle)

*/

Static int

Child_make (struct child_s * PTR)

{

Pid_t PID;



If (pid = fork ())! = 0)

Return PID;/* parent process */



/*

* Reset the number of sub-Processes

*/

Signal (sigchld, sig_dfl );

Signal (sigterm, sig_dfl );

Signal (sighup, sig_dfl );



Child_main (PTR);/* will not return */



Return-1;

}



Int

Child_pool_create (void)

{

/* Sleep (10 );*/

Child_ptr = (struct child_s *)

Calloc_shared_memory (maxclients,

Sizeof (struct child_s ));

If (child_ptr = map_failed ){

Fprintf (stderr, "cocould not allocate shared memory for children./N ");

Return-1;

}



Servers_waiting = (unsigned int *)

Malloc_shared_memory (sizeof (unsigned INT ));

If (servers_waiting = map_failed ){

Fprintf (stderr, "cocould not allocate shared memory for child counting./N ");

Return-1;

}

* Servers_waiting = 0;


/* Create and add the hosts file before the servers_waiting change operation */

_ Child_lock_init ();


Int I;

/* Initialize the sub-progress shared data group */

For (I = 0; I <maxclients; I ++ ){

Child_ptr.Status = t_empty;

Child_ptr.connects = 0;

}



/* Fork sub-progress */

For (I = 0; I <startservers; I ++ ){

Child_ptr.status = t_waiting;

Child_ptr.tid = child_make (& child_ptr );



If (child_ptr.tid <0 ){

Fprintf (stderr,

"Cocould not create child Number % d of % d/N ",

I, startservers );

Return-1;

} Else {

Fprintf (stderr,

"Creating child Number % d of % d.../N ",

I + 1, startservers );



Server_inc ();

}

}


Return 0;

}



/*

* Except all service flows

*/

Void

Kill_children (void)

{

Unsigned int I;


For (I = 0; I <maxclients; I ++ ){

If (child_ptr.status! = T_empty)

Kill (child_ptr.tid, sigterm );

}

}



/*

* The traffic control process is mainly used to maintain the number of service flows in a combined volume.

*/

Void

Child_main_loop (void)

{

Unsigned int I;



While (1 ){

If (quit)

Return;



/* If the number of blank service flows is insufficient, create a number */

Server_count_lock ();

If (* servers_waiting <minspareservers ){

Fprintf (stderr,

"Waiting servers (% d) is less than minspareservers (% d). Creating new child .",

* Servers_waiting, minspareservers );



Server_count_unlock ();



For (I = 0; I <maxclients; I ++ ){

If (child_ptr.status = t_empty ){

Child_ptr.status = t_waiting;

Child_ptr.tid = child_make (& child_ptr );

If (child_ptr.tid <0 ){

Fprintf (stderr, "cocould not create child ");



Child_ptr.status = t_empty;

Break;

}



Server_inc ();



Break;

}

}

} Else {

Server_count_unlock ();

}



Sleep (5 );



If (inclued_sighup ){

/* After receiving the HUP Token, you can perform some sort operations, such as updating the original log file */

Received_sighup = 0;

}

}

}



/*

* Handling email

*/

Void

Takesig (INT sig)

{

Pid_t PID;

Int status;



Switch (SIG ){

Case sighup:

Received_sighup = 1;

Break;



Case sigterm:

Quit = 1;

Break;



Case sigchld:

While (pid = waitpid (-1, & status, wnohang)> 0)

;

Break;

}



Return;

}



Int

Main (INT argc, char ** argv)

{

Int godaemon = 1;/* indicates whether the deamon mode is used */

Unsigned short Port = port;/* Service port restart */



Assert (minspareservers <= maxspareservers );

Assert (startservers <= maxclients );

Assert (maxclients <= maxlisten );


If (godaemon = 1 ){

Daemon (1, 1 );

}


/* Activate the mobile server socket */

Start_listen_socket (port );


Signal (sigpipe, sig_ign );


/* Create a service progress Group */

Child_pool_create ();



/*

* The following information processing functions are only useful for traffic control processes.

*/

Signal (sigchld, takesig );

Signal (sigterm, takesig );

Signal (sighup, takesig );


/* Start traffic control */

Child_main_loop ();


/* Cancel the service progress group before exiting */

Kill_children ();


/* Connect to the service socket */

Close_listen_socket ();


Exit (0 );

Return 0;

}



/*

* In this function, the handling handler for customer requests is listed below.

* When the processing is completed and the function is exited, The connfd is involved.

* This is just an example!

*/

Void

Handle_connection (INT connfd)

{

Char Buf [128] = {};

Sprintf (BUF, "% u:", (unsigned INT) getpid ());

Int Len = strlen (BUF );

Read (connfd, BUF + Len, sizeof (BUF)-len-1 );

Len = strlen (BUF );

Write (connfd, Buf, Len );


Close (connfd );

}

 

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.