linux下多進程服務框架

本文介绍了一个基于tinyproxy改編的多进程Web服务器框架。该框架通过定义一系列常量来控制服务进程的数量,并实现了信号处理及进桯组控制。用户只需实现handle_connection函数来处理客户端请求。
部署运行你感兴趣的模型镜像
提示:改編自tinyproxy,向原作者致敬!

在程序的開頭,可以定義以下几個常量:

#defineMAXSERVICES	128	/*每一個進程最大服務用戶數,防止錯誤積累*/

#defineSTARTSERVERS 32 /*初始啟動服務進程數*/

#defineMAXSPARESERVERS 32 /*最大空閒服務進程數*/

#defineMINSPARESERVERS 8 /*最小空閒服務進程數*/


使用者只需要在程序最下面修改handle_connection函數,在裡面實現對客戶請求的處理邏輯即可,信號處理及進程組控制都由框架完成。在RHES32.4kernel和DebianEtch2.6kernel下測試通過。


歡迎指正。
#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>



/*

*福瑞哈哥改編自tinyproxy

*/



#defineMAXLISTEN 1024 /*最大監聽數,listen函數用*/

#defineMAXCLIENTS 64 /*最大服務進程數*/

#defineMAXSERVICES 128 /*每一個進程最大服務用戶數,定期更新進程組,防止錯誤積累*/

#defineSTARTSERVERS 32 /*初始啟動服務進程數*/

#defineMAXSPARESERVERS 32 /*最大空閒服務進程數*/

#defineMINSPARESERVERS 8 /*最小空閒服務進程數*/



#definePORT 8000 /*監聽端口號*/



/*全局變量區*/

intlistenfd; /*服務socket*/

intreceived_sighup=0; /*收到hup信號標誌*/

intquit=0; /*退出標誌*/



#defineSERVER_COUNT_LOCK()_child_lock_wait()

#defineSERVER_COUNT_UNLOCK()_child_lock_release()



/*共享變量鎖*/

staticstructflocklock_it,unlock_it;

staticintlock_fd=-1;



enumchild_status_t{T_EMPTY,T_WAITING,T_CONNECTED};



structchild_s{

pid_ttid;

unsignedintconnects;

enumchild_status_tstatus;

};



/*

*子進程數組-位於共享內存區

*/

staticstructchild_s*child_ptr;



/*

*正等待用戶連接的服務進程數

*/

staticunsignedint*servers_waiting;



/*

*分配一塊共享內存。

*/

staticvoid*

malloc_shared_memory(size_tsize)

{

intfd;

void*ptr;

charbuffer[32];



staticchar*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);



returnptr;

}



/*

*分配一塊共享內存,並清0。

*/

staticvoid*

calloc_shared_memory(size_tnmemb,size_tsize)

{

void*ptr;

longlength;



assert(nmemb>0);

assert(size>0);



length=nmemb*size;



ptr=malloc_shared_memory(length);

if(ptr==MAP_FAILED)

returnptr;



memset(ptr,0,length);



returnptr;

}



staticvoid

_child_lock_init(void)

{

charlock_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;

}



staticvoid

_child_lock_wait(void)

{

intrc;



while((rc=fcntl(lock_fd,F_SETLKW,&lock_it))<0){

if(errno==EINTR)

continue;

else

return;

}

}



staticvoid

_child_lock_release(void)

{

if(fcntl(lock_fd,F_SETLKW,&unlock_it)<0)

return;

}



#defineSERVER_INC()do{/

SERVER_COUNT_LOCK();/

++(*servers_waiting);/

SERVER_COUNT_UNLOCK();/

}while(0)



#defineSERVER_DEC()do{/

SERVER_COUNT_LOCK();/

assert(*servers_waiting>0);/

--(*servers_waiting);/

SERVER_COUNT_UNLOCK();/

}while(0)



/*

*創建監聽socket

*/

staticvoid

start_listen_socket(unsignedshortport)

{

intsockfd;

inton=1;

structsockaddr_inaddr;


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);

/*

*需要指定到實際的地址上

*/

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


if(bind(sockfd,(structsockaddr*)&addr,sizeof(addr))<0){

fprintf(stderr,"Unabletobindlisteningsocketbecauseof%s/n",

strerror(errno));

exit(-1);

}


if(listen(sockfd,MAXLISTEN)<0){

fprintf(stderr,"Unabletostartlisteningsocketbecauseof%s/n",

strerror(errno));

exit(-1);

}


listenfd=sockfd;

}



void

close_listen_socket(void)

{

close(listenfd);

}



/*

*在這個函數中,寫下對客戶請求的處理邏輯。

*處理完成後在退出這個函數時,關閉connfd。

*/

void

handle_connection(intconnfd);



/*

*子進程主循環

*/

staticvoid

child_main(structchild_s*ptr)

{

intconnfd;

structsockaddr*cliaddr;

socklen_tclilen;


clilen=sizeof(structsockaddr);

cliaddr=(structsockaddr*)malloc(clilen);

if(!cliaddr){

fprintf(stderr,

"Couldnotallocatememoryforchildaddress.");

exit(0);

}



ptr->connects=0;



while(!quit){

ptr->status=T_WAITING;



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



/*

*保證沒有錯誤發生

*/

if(connfd<0){

fprintf(stderr,

"Acceptreturnedanerror(%s)...retrying.",

strerror(errno));

continue;

}



ptr->status=T_CONNECTED;



SERVER_DEC();



handle_connection(connfd);

ptr->connects++;



if(ptr->connects==MAXSERVICES){

fprintf(stderr,

"ChildhasreachedMaxRequestsPerChild(%u).Killingchild./n",

ptr->connects);

break;

}



SERVER_COUNT_LOCK();

if(*servers_waiting>MAXSPARESERVERS){

/*

*有太多空閒服務進程,退出自己

*/

fprintf(stderr,

"Waitingservers(%d)exceedsMaxSpareServers(%d).Killingchild./n",

*servers_waiting,MAXSPARESERVERS);

SERVER_COUNT_UNLOCK();



break;

}else{

SERVER_COUNT_UNLOCK();

}



SERVER_INC();

}



ptr->status=T_EMPTY;



free(cliaddr);

exit(0);

}



/*

*Fork一個子進程並啟動child_main()函數(子進程主循環)

*/

staticint

child_make(structchild_s*ptr)

{

pid_tpid;



if((pid=fork())!=0)

returnpid; /*父進程*/



/*

*重設子進程的信號處理函數

*/

signal(SIGCHLD,SIG_DFL);

signal(SIGTERM,SIG_DFL);

signal(SIGHUP,SIG_DFL);



child_main(ptr);/*不會返回*/



return-1;

}



int

child_pool_create(void)

{

/*sleep(10);*/

child_ptr=(structchild_s*)

calloc_shared_memory(MAXCLIENTS,

sizeof(structchild_s));

if(child_ptr==MAP_FAILED){

fprintf(stderr,"Couldnotallocatesharedmemoryforchildren./n");

return-1;

}



servers_waiting=(unsignedint*)

malloc_shared_memory(sizeof(unsignedint));

if(servers_waiting==MAP_FAILED){

fprintf(stderr,"Couldnotallocatesharedmemoryforchildcounting./n");

return-1;

}

*servers_waiting=0;


/*在操作servers_waiting變量之前,創建加鎖文件*/

_child_lock_init();


inti;

/*初始化子進程共享數組*/

for(i=0;i<MAXCLIENTS;i++){

child_ptr.status=T_EMPTY;

child_ptr.connects=0;

}



/*fork子進程*/

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,

"Couldnotcreatechildnumber%dof%d/n",

i,STARTSERVERS);

return-1;

}else{

fprintf(stderr,

"Creatingchildnumber%dof%d.../n",

i+1,STARTSERVERS);



SERVER_INC();

}

}


return0;

}



/*

*刪除所有服務進程

*/

void

kill_children(void)

{

unsignedinti;


for(i=0;i<MAXCLIENTS;i++){

if(child_ptr.status!=T_EMPTY)

kill(child_ptr.tid,SIGTERM);

}

}



/*

*監控進程主循環,它負責把服務進程的數量維持在一個合適的數量上。

*/

void

child_main_loop(void)

{

unsignedinti;



while(1){

if(quit)

return;



/*如果空閒服務進程數不足,則創建一些*/

SERVER_COUNT_LOCK();

if(*servers_waiting<MINSPARESERVERS){

fprintf(stderr,

"Waitingservers(%d)islessthanMinSpareServers(%d).Creatingnewchild.",

*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,"Couldnotcreatechild");



child_ptr.status=T_EMPTY;

break;

}



SERVER_INC();



break;

}

}

}else{

SERVER_COUNT_UNLOCK();

}



sleep(5);



if(received_sighup){

/*在收到hup信號後,可作一些維護工作,比如更新備份日志文件等*/

received_sighup=0;

}

}

}



/*

*處理信號

*/

void

takesig(intsig)

{

pid_tpid;

intstatus;



switch(sig){

caseSIGHUP:

received_sighup=1;

break;



caseSIGTERM:

quit=1;

break;



caseSIGCHLD:

while((pid=waitpid(-1,&status,WNOHANG))>0)

;

break;

}



return;

}



int

main(intargc,char**argv)

{

intgodaemon=1; /*是否轉為deamon模式*/

unsignedshortport=PORT; /*服務端口號*/



assert(MINSPARESERVERS<=MAXSPARESERVERS);

assert(STARTSERVERS<=MAXCLIENTS);

assert(MAXCLIENTS<=MAXLISTEN);


if(godaemon==1){

daemon(1,1);

}


/*啟動服務socket*/

start_listen_socket(port);


signal(SIGPIPE,SIG_IGN);


/*創建服務進程組*/

child_pool_create();



/*

*下面這些信號處理函數只有監控進程才有用

*/

signal(SIGCHLD,takesig);

signal(SIGTERM,takesig);

signal(SIGHUP,takesig);


/*開始監控工作*/

child_main_loop();


/*退出前,殺掉服務進程組*/

kill_children();


/*關閉服務socket*/

close_listen_socket();


exit(0);

return0;

}



/*

*在這個函數中,寫下對客戶請求的處理邏輯。

*處理完成後在退出這個函數時,關閉connfd。

*這只是一個示例!

*/

void

handle_connection(intconnfd)

{

charbuf[128]={};

sprintf(buf,"%u:",(unsignedint)getpid());

intlen=strlen(buf);

read(connfd,buf+len,sizeof(buf)-len-1);

len=strlen(buf);

write(connfd,buf,len);


close(connfd);

}

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值