linux下的多进程服务器框架

提示:改編自tinyproxy,向原作者致敬!

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

#defineMAXSERVICES        128       
#define STARTSERVERS 
      32       
#define MAXSPARESERVERS 
      32       
#define MINSPARESERVERS 
           


使用者只需要在程序最下面修改handle_connection函數,在裡面實現對客戶請求的處理邏輯即可,信號處理及進程組控制都由框架完成。在RHES3 2.4kernel和Debian Etch 2.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>



#define MAXLISTEN 
              1024               
#define MAXCLIENTS 
              64                       
#define MAXSERVICES 
              128                       
#define STARTSERVERS 
      32                       
#define MAXSPARESERVERS 
      32                       
#define MINSPARESERVERS 
                           

#define PORT  
                      8000               


int listenfd;  
                             
int received_sighup = 0; 
     
int quit = 0; 
                             

#define SERVER_COUNT_LOCK() 
  _child_lock_wait()
#define SERVER_COUNT_UNLOCK() _child_lock_release()


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


static struct child_s *child_ptr;


static unsigned int* servers_waiting;


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


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)


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);
 
     
 
      addr.sin_addr.s_addr = inet_addr( "0.0.0.0");
 
     
 
      if ( bind( sockfd, (struct sockaddr *)&addr, sizeof (addr) ) < 0 ) {
 
              fprintf( stderr, "Unable tobind listening socket because of %s\n",
 
                                  strerror(errno));
 
              exit(-1);
 
      }
 
     
 
      if ( listen( sockfd, MAXLISTEN )< 0 ) {
 
              fprintf( stderr, "Unable tostart listening socket because of %s\n",
 
                              strerror(errno) );
 
              exit(-1);
 
      }
 
     
 
      listenfd = sockfd;
}

void
close_listen_socket(void)
{
 
      close( listenfd );
}


void
handle_connection( int connfd );


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,
 
                              "Could notallocate memory for child address." );
 
              exit(0);
 
      }

 
      ptr->connects = 0;

 
      while ( !quit ) {
 
              ptr->status =T_WAITING;

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

 
             
 
              if ( connfd <0 ) {
 
                      fprintf(stderr,
 
                                          "Acceptreturned 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 hasreached MaxRequestsPerChild (%u). Killing child.\n",
 
                                          ptr->connects);
 
                      break;
 
              }

 
              SERVER_COUNT_LOCK();
 
              if ( *servers_waiting> MAXSPARESERVERS ) {
 
                     
 
                      fprintf(stderr,
 
                                          "Waitingservers (%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);
}


static int
child_make( struct child_s* ptr )
{
 
      pid_t pid;

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

 
     
 
      signal( SIGCHLD, SIG_DFL );
 
      signal( SIGTERM, SIG_DFL );
 
      signal( SIGHUP, SIG_DFL );

 
      child_main(ptr);

 
      return -1;
}

int
child_pool_create(void)
{
 
     
 
      child_ptr = (struct child_s*)
 
              calloc_shared_memory(MAXCLIENTS,
 
                                                          sizeof(struct child_s) );
 
      if ( child_ptr == MAP_FAILED ) {
 
              fprintf( stderr, "Could notallocate shared memory for children.\n" );
 
              return -1;
 
      }

 
      servers_waiting = (unsigned int*)
 
              malloc_shared_memory(sizeof(unsigned int) );
 
      if ( servers_waiting == MAP_FAILED ) {
 
              fprintf( stderr, "Could notallocate shared memory for child counting.\n" );
 
              return -1;
 
      }
 
      *servers_waiting = 0;
 
     
 
     
 
      _child_lock_init();
 
     
 
      int i;
 
     
 
      for ( i = 0; i < MAXCLIENTS; i++) {
 
              child_ptr[i].status =T_EMPTY;
 
              child_ptr[i].connects =0;
 
      }

 
     
 
      for ( i = 0; i < STARTSERVERS;i++ ) {
 
              child_ptr[i].status =T_WAITING;
 
              child_ptr[i].tid =child_make( &child_ptr[i] );

 
              if ( child_ptr[i].tid< 0 ) {
 
                      fprintf(stderr,
 
                                      "Could notcreate child number %d of %d\n",
 
                                      i,STARTSERVERS );
 
                      return-1;
 
              } else {
 
                      fprintf(stderr,
 
                                      "Creatingchild number %d of %d ...\n",
 
                                      i + 1,STARTSERVERS );

 
                      SERVER_INC();
 
              }
 
      }
 
     
 
      return 0;
}


void
kill_children(void)
{
 
      unsigned int i;
 
     
 
      for ( i = 0; i < MAXCLIENTS; i++) {
 
              if ( child_ptr[i].status !=T_EMPTY )
 
                      kill(child_ptr[i].tid, SIGTERM );
 
      }
}


void
child_main_loop(void)
{
 
      unsigned int i;

 
      while (1) {
 
              if ( quit )
 
                      return;

 
             
 
              SERVER_COUNT_LOCK();
 
              if ( *servers_waiting< MINSPARESERVERS ) {
 
                      fprintf(stderr,
 
                                          "Waitingservers (%d) is less than MinSpareServers (%d). Creating newchild.",
 
                                          *servers_waiting,MINSPARESERVERS );

 
                      SERVER_COUNT_UNLOCK();

 
                      for ( i =0; i < MAXCLIENTS; i++ ) {
 
                              if ( child_ptr[i].status == T_EMPTY ) {
 
                                      child_ptr[i].status =T_WAITING;
 
                                      child_ptr[i].tid =child_make( &child_ptr[i] );
 
                                      if ( child_ptr[i].tid< 0 ) {
 
                                              fprintf(stderr, "Could not create child" );

 
                                              child_ptr[i].status = T_EMPTY;
 
                                              break;
 
                                      }

 
                                      SERVER_INC();

 
                                      break;
 
                              }
 
                      }
 
              } else {
 
                      SERVER_COUNT_UNLOCK();
 
              }

 
              sleep(5);

 
              if ( received_sighup ){
 
                     
 
                      received_sighup = 0;
 
              }
 
      }
}


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;                                        
 
      unsigned short port = PORT;                

 
      assert( MINSPARESERVERS <=MAXSPARESERVERS );
 
      assert( STARTSERVERS <=MAXCLIENTS );
 
      assert( MAXCLIENTS <= MAXLISTEN);
 
     
 
      if ( godaemon == 1 ) {
 
              daemon(1, 1);
 
      }
 
     
 
     
 
      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();
 
     
 
     
 
      close_listen_socket();
 
     
 
      exit(0);
 
      return 0;
}


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

Webadmin!是一个免费的开源框架,用于为Linux系统的快速搭建统一、稳定、易用的Web管理系统。 WebAdmin系统由三部分组成:WEB图形用户接口、WebAdmin守护进程和进程监视程序。Web图形用户接口(WebGUI)是WebAdmin系统的前端部分,为用户提供一个统一、易操作的图形界面。WebAdmin守护进程 (WebAdmind)是WebAdmin系统的后台部分,实时监视WebGUI生成的配置文件,并根据配置文件的变化情况,启动或停止相应的服务进程,WebAdmin进程监视程序(DaemonWatcher)用于实时监视WebAdmind启动的服务进程的运行状况,一旦发现启动的服务进程异常中止,立即重启中止的服务进程,从而确保系统可靠稳定运行。 WebAdmin!提供了一个结构化的WebAdmin开发框架,它的前后台部分均采用插件式的程序开发方法,借助提供的插件开发模板,WebAdmin系统开发者不必关WebAdmin开发框架的具体实现,就可设计出界面统一、操作简单、安全稳定的WebGUI界面。与WebGUI相对应,Webadmind也是采用插件式的程序开发方法。WebAdmind插件与WebGUI插件一一对应完成对界面操作的响应。DaemonWatcher是一个独立的进程监视程序,是为确保WebAdmind启动的进程能够不可间断地提供服务,一旦发现被监视程序发生异常中止,DaemonWatcher将根据进程的启动脚本立即启动被中止进程。 WebAdmin是一个用C语言设计的易用的图形用户接口开发框架,C语言的高可移植性使得WebAdmin可以广泛应用于包括Linux、Unix、Windows及各种嵌入式操作系统中,编译WebAdmin系统除Libxml2库处不需要额外的C函数库支持。WebAdmin提供了丰富的API函数,开发者可以根据自己的需要定制个性化的WebAdmin系统。 WebAdmin系统的界面风格也可以自己定制,对于OEM厂商可以根据需要修改界面风格,满足定制要求。 WebAdmin的开放设计思想,为WebAdmin系统的不断发展普奠定了基础,无数开发者提供了开源插件模块,用户甚至不用写一行代码就可根据自己的需要设计WebAdmin系统。 【简单使用方法】:下载后将压缩文件上传到Linux系统中,用tar xvfz webadmin-devel-1.3.tar.gz解压,解压后进入webadmin-devel目录,执行./configure,make命令后将会在test/webui目录下生成一个webadmin.cgi文件,将此文件拷贝到apache下的WEB根目录下cgi-bin目录下即可,为测试webadmin.cgi,还需将htdocs目录下的文件拷贝到apache的WEB根目录下,将etc目录中的所有文件拷贝到根目录下的etc中,最后用浏览器访问你的apache Web服务器即可看到Linux系统的WEB管理界面。 【说明】:编译此源码需要libxml2库的支持 有技术问题可以访问官方网站:http://www.webadminc.com,联系电话:13311223928
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值