相似ngnix的多進程監聽用例

多進程監聽適合於短鏈接,且鏈接間無交集的應用。
前兩天簡單寫了一個,在這裏保存一下。
socket

  1. #include <sys/types.h>
    測試

  2. #include <stdarg.h>
    ui

  3. #include <signal.h>
    spa

  4. #include <unistd.h>
    線程

  5. #include <fcntl.h>
    日誌

  6. #include <time.h>
    orm

  7. #include <string.h>
    server

  8. #include <stdlib.h>
    進程

  9. #include <stdio.h>
    get

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


複製代碼

相關文章
相關標籤/搜索