找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 2874|回复: 0

类似ngnix的多进程监听用例

[复制链接]
发表于 2014-4-23 13:10:44 | 显示全部楼层 |阅读模式
多进程监听适合于短连接,且连接间无交集的应用。
前两天简单写了一个,在这里保存一下。
  1. #include <sys/types.h>
  2. #include <stdarg.h>
  3. #include <signal.h>
  4. #include <unistd.h>
  5. #include <fcntl.h>
  6. #include <time.h>
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <errno.h>
  11. #include <sys/socket.h>  
  12. #include <arpa/inet.h>
  13. char * ToDateStr(time_t tt, char *szDateTime, const char *szFormat)
  14. {
  15.         size_t i, len;
  16.         char field[3], c1 = ' ', c2 = '-', c3 = ':', c4 = '/'; /* 常见的分隔符 */
  17.         char *p;
  18.         struct tm result;
  19.         if (szDateTime == NULL)
  20.         {
  21.                 return NULL;
  22.         }
  23.        
  24.         localtime_r(&tt, &result);
  25.         /* 默认的格式 yyyy-mm-dd hh:mi:ss*/
  26.         if (szFormat == NULL)
  27.         {
  28.                 sprintf(szDateTime, "%04d-%02d-%02d %02d:%02d:%02d",
  29.                         result.tm_year + 1900, result.tm_mon + 1, result.tm_mday,
  30.                         result.tm_hour, result.tm_min, result.tm_sec);
  31.                
  32.                 szDateTime[strlen("yyyy-mm-dd hh:mi:ss")] = '\0';
  33.                 return szDateTime;
  34.         }
  35.        
  36.         /* 用户指定格式 */
  37.         len = strlen(szFormat);
  38.         i = 0;
  39.         p = szDateTime;
  40.        
  41.         /* 判断前4个字符是否为yyyy */
  42.         if (strncmp(szFormat, "yyyy", 4) == 0)
  43.         {
  44.                 sprintf(p, "%04d", result.tm_year + 1900);
  45.                 p += 4;
  46.                 i += 4;
  47.         }
  48.         /* 格式中的剩余部分 */
  49.         while (i < len)
  50.         {
  51.                 /* 格式中的每个域必须以两个紧邻字符为整体 */
  52.                 field[0] = szFormat[i];
  53.                 i += 1;
  54.                
  55.                 if (field[0] != c1 && field[0] != c2 && field[0] != c3 && field[0] != c4) /* 如果第一个字符不是分隔符 */
  56.                 {
  57.                         field[1] = szFormat[i];
  58.                         field[2] = '\0';
  59.                         i += 1;
  60.                        
  61.                         if (strcmp(field, "yy") == 0) /* 这种情况下整个格式里最多有两个yy */
  62.                         {
  63.                                 sprintf(p, "%02d", (result.tm_year + 1900) % 100);
  64.                         }
  65.                         else if (strcmp(field, "mm") == 0)
  66.                         {
  67.                                 sprintf(p, "%02d", result.tm_mon + 1);
  68.                         }
  69.                         else if (strcmp(field, "dd") == 0)
  70.                         {
  71.                                 sprintf(p, "%02d", result.tm_mday);
  72.                         }
  73.                         else if (strcmp(field, "hh") == 0)
  74.                         {
  75.                                 sprintf(p, "%02d", result.tm_hour);
  76.                         }
  77.                         else if (strcmp(field, "mi") == 0)
  78.                         {
  79.                                 sprintf(p, "%02d", result.tm_min);
  80.                         }
  81.                         else if (strcmp(field, "ss") == 0)
  82.                         {
  83.                                 sprintf(p, "%02d", result.tm_sec);
  84.                         }
  85.                         else
  86.                         {
  87.                                 return NULL;
  88.                         }
  89.                        
  90.                         p += 2;
  91.                 }
  92.                 else /* 如果是分隔符则直接打印出来 */
  93.                 {
  94.                         *p = field[0];
  95.                         p += 1;
  96.                 }
  97.         }
  98.        
  99.         *p = '\0';
  100.        
  101.         return szDateTime;
  102. }
  103. //时间格式化
  104. char * Now(char *szDateTime, const char *szFormat)
  105. {
  106.         return ToDateStr(time(NULL), szDateTime, szFormat);
  107. }
  108. //写日志文件
  109. void mlog(char *logFileName,char *fmt,...)
  110. {
  111.         char        log_path[128];
  112.         char        date_time[20];
  113.         char        date_str[10];
  114.         char        time_str[10];
  115.        
  116.         FILE         *fp;
  117.         va_list        varArg;
  118.         char        buf_str[1024];
  119.        
  120.         memset(log_path,  0, sizeof(log_path));
  121.         memset(date_time, 0, sizeof(date_time));
  122.         memset(date_str,  0, sizeof(date_str));
  123.         memset(time_str,  0, sizeof(time_str));
  124.         memset(buf_str,   0, sizeof(buf_str));
  125.        
  126.         // 取日期及时间
  127.         Now(date_time, "yyyymmddhh:mi:ss");
  128.         memcpy(date_str, date_time, 8);
  129.         memcpy(time_str, date_time + 8, 8);
  130.        
  131.         /* 组合日志文件目录 */
  132.         sprintf(log_path, "./%s.%s", logFileName, date_str);
  133.         /* 以(创建)追加方式打开日志文件 */
  134.         fp = fopen(log_path, "a+");
  135.         if(fp == NULL)
  136.         {
  137.                 return;
  138.         }
  139.        
  140.         va_start(varArg, fmt);
  141.         vsprintf(buf_str, fmt, varArg);
  142.         va_end(varArg);
  143.         fprintf(fp, "%s: %s\n", time_str, buf_str);       
  144.        
  145.         fclose(fp);
  146. }
  147. //写独占文件锁
  148. int AcquireWriteLock(int fd, int start, int len)
  149. {
  150.         struct flock arg;
  151.         arg.l_type = F_WRLCK; // 加写锁
  152.         arg.l_whence = SEEK_SET;
  153.         arg.l_start = start;
  154.         arg.l_len = len;
  155.         arg.l_pid = getpid();
  156.         return fcntl(fd, F_SETLKW, &arg);
  157. }
  158. //释放独占文件锁
  159. int ReleaseLock(int fd, int start, int len)
  160. {
  161.         struct flock arg;
  162.         arg.l_type = F_UNLCK; //  解锁
  163.         arg.l_whence = SEEK_SET;
  164.         arg.l_start = start;
  165.         arg.l_len = len;
  166.         arg.l_pid = getpid();
  167.         return fcntl(fd, F_SETLKW, &arg);
  168. }
  169. //查看写锁
  170. int SeeLock(int fd, int start, int len)
  171. {
  172.         struct flock arg;
  173.         arg.l_type = F_WRLCK;
  174.         arg.l_whence = SEEK_SET;
  175.         arg.l_start = start;
  176.         arg.l_len = len;
  177.         arg.l_pid = getpid();
  178.         if (fcntl(fd, F_GETLK, &arg) != 0) // 获取锁
  179.         {
  180.                 return -1; // 测试失败
  181.         }
  182.         if (arg.l_type == F_UNLCK)
  183.         {
  184.                 return 0; // 无锁
  185.         }
  186.         else if (arg.l_type == F_RDLCK)
  187.         {
  188.                 return 1; // 读锁
  189.         }
  190.         else if (arg.l_type == F_WRLCK)
  191.         {
  192.                 return 2; // 写所
  193.         }
  194.         return 0;
  195. }
  196. int Chlid_Run(int nServerfd)
  197. {
  198.         socklen_t nClientAddrSize = 0;
  199.         int nClientfd       = -1;
  200.         struct sockaddr_in Clientaddr;
  201.        
  202.         //循环监听接收数据
  203.         while(1)  
  204.         {  
  205.                 nClientAddrSize = sizeof(struct sockaddr_in);
  206.                
  207.                 nClientfd = accept(nServerfd, (struct sockaddr *)(&Clientaddr), &nClientAddrSize);
  208.                 if(-1 == nClientfd)  
  209.                 {  
  210.                     printf("[Chlid_Run]accept fail !\n");  
  211.                     return -1;
  212.                 }
  213.                
  214.                 //随便返回一个数据
  215.                 char szReturn[20];
  216.                 sprintf(szReturn, "hello");
  217.                 if(-1 == write(nClientfd, szReturn, strlen(szReturn)))  
  218.                 {
  219.             mlog((char* )"process", (char* )"[Chlid_Run](%s:%d)(%d)Connected Send error!", inet_ntoa(Clientaddr.sin_addr), ntohs(Clientaddr.sin_port), getpid());  
  220.             return -1;  
  221.                 }
  222.                
  223.                 //打印进程ID
  224.                 mlog((char* )"process", (char* )"[Chlid_Run](%s:%d)Connected pid=%d!", inet_ntoa(Clientaddr.sin_addr), ntohs(Clientaddr.sin_port), getpid());  
  225.                
  226.                 //关闭socket连接
  227.                 close(nClientfd);
  228.         }
  229. }
  230. int main(int argc, char *argv[])
  231. {
  232.         //当前监控子线程个数
  233.         int nNumChlid = 5;
  234.        
  235.         //检测时间间隔参数
  236.         struct timespec tsRqt;
  237.        
  238.         //文件锁
  239.         int fd_lock = 0;
  240.        
  241.         //要监听的IP和端口
  242.         struct sockaddr_in server_addr;
  243.         struct sockaddr_in client_addr;
  244.         int nPort = 10030;    //监听端口
  245.         int nServerfd = 0;    //Server Socket
  246.        
  247.         int nRet = 0;
  248.         //主进程检测时间间隔(设置每隔5秒一次)
  249.   tsRqt.tv_sec  = 5;
  250.         tsRqt.tv_nsec = 0;
  251.        
  252.         // 打开(创建)锁文件
  253.         char szFileName[200] = {'\0'};
  254.         memset(szFileName, 0, sizeof(flock));
  255.         sprintf(szFileName, "./MultiListen.lk", getenv("HOME"));
  256.         fd_lock = open(szFileName, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
  257.         if (fd_lock < 0)
  258.         {
  259.                 printf("open the flock and exit, errno = %d.", errno);
  260.                 exit(1);
  261.         }
  262.        
  263.         //查看当前文件锁是否已锁
  264.         nRet = SeeLock(fd_lock, 0, sizeof(int));
  265.         if (nRet == -1 || nRet == 2)
  266.         {
  267.                 printf("file is already exist!");
  268.                 exit(1);
  269.         }
  270.        
  271.         //如果文件锁没锁,则锁住当前文件锁
  272.   if (AcquireWriteLock(fd_lock, 0, sizeof(int)) != 0)
  273.         {
  274.                 printf("lock the file failure and exit, idx = 0!.");
  275.                 exit(1);
  276.         }
  277.        
  278.         //写入子进程锁信息
  279.         lseek(fd_lock, 0, SEEK_SET);
  280.         for (int nIndex = 0; nIndex <= nNumChlid; nIndex++)
  281.   {
  282.           write(fd_lock, &nIndex, sizeof(nIndex));
  283.   }
  284.   
  285.   //在这里初始化监听
  286.   nServerfd = socket(AF_INET, SOCK_STREAM, 0);
  287.   if(-1 == nServerfd)
  288.   {
  289.           printf("[Main]Create Server FD error.\n");
  290.           return -1;
  291.   }
  292.   
  293.   //初始化监听地址信息
  294.   bzero(&server_addr,sizeof(struct sockaddr_in));  
  295.         server_addr.sin_family=AF_INET;  
  296.         server_addr.sin_addr.s_addr=htonl(INADDR_ANY); /* 这里地址使用全0,即所有 */  
  297.         server_addr.sin_port=htons(nPort);
  298.   
  299.   //绑定Socket FD
  300.   if(-1 == bind(nServerfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)))  
  301.         {  
  302.     printf("[main]bind server addr fail!\n");  
  303.     return -1;  
  304.         }
  305.        
  306.         //开始监听
  307.         if(-1 == listen(nServerfd, 5))  
  308.         {  
  309.     printf("[main]listen server fail!\r\n");  
  310.     return -1;  
  311.         }
  312.        
  313.        
  314.   
  315.   while (1)
  316.   {
  317.           for (int nChlidIndex = 1; nChlidIndex <= nNumChlid; nChlidIndex++)
  318.           {
  319.                      //测试每个子进程的锁是否还存在
  320.                      nRet = SeeLock(fd_lock, nChlidIndex * sizeof(int), sizeof(int));
  321.                      if (nRet == -1 || nRet == 2)
  322.                      {
  323.                              continue;
  324.                      }
  325.                      //如果文件锁没有被锁,则设置文件锁,并启动子进程
  326.                      int npid = fork();
  327.                      if (npid == 0)
  328.                      {
  329.                              //上文件锁
  330.                              if(AcquireWriteLock(fd_lock, nChlidIndex * sizeof(int), sizeof(int)) != 0)
  331.                 {
  332.                         printf("child %d AcquireWriteLock failure.\n", nChlidIndex);
  333.                         exit(1);
  334.                 }
  335.                 
  336.                 //启动子进程
  337.                 Chlid_Run(nServerfd);
  338.                 
  339.                                         //子进程在执行完任务后必须退出循环和释放锁
  340.                                         //ReleaseLock(fd_lock, nChlidIndex * sizeof(int), sizeof(int));                
  341.                      }
  342.           }
  343.          
  344.           printf("child count(%d) is ok.\n", nNumChlid);
  345.           //检查间隔
  346.           nanosleep(&tsRqt, NULL);
  347.   }
  348.        
  349.         return 0;
  350. }
复制代码


您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-5-4 11:06 , Processed in 0.023145 second(s), 7 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表