博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
类似ngnix的多进程监听用例
阅读量:6981 次
发布时间:2019-06-27

本文共 6694 字,大约阅读时间需要 22 分钟。

hot3.png

多进程监听适合于短连接,且连接间无交集的应用。

前两天简单写了一个,在这里保存一下。

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

复制代码

转载于:https://my.oschina.net/u/2273582/blog/346311

你可能感兴趣的文章
python3 集合中的常用方法
查看>>
ECSHOP生成缩略图模糊
查看>>
LayaAir疑难杂症之四:laya引擎自动断点到bundle.js文件中且无报错,但程序不再执行...
查看>>
元组操作
查看>>
mysql官方下载
查看>>
输入:一行数据空格隔开
查看>>
【Swift】UILabel 设置内边距
查看>>
Swift值类型和引用类型的内存储存情况
查看>>
pyhon简单比较文本相似度的方法
查看>>
web前端整套面试题(二)--今日头条面试题
查看>>
一些东西,复制
查看>>
bi api 软件
查看>>
WPS客户端更新日志留着备用
查看>>
c#获取电脑硬件信息参数说明(内存篇 Win32_PhysicalMemory)
查看>>
LeetCode算法题-Balanced Binary Tree(Java实现)
查看>>
Cocos2dx 3.1.1 将一个2.X的项目改成3.1版本
查看>>
12.12冲刺~!
查看>>
sql知识
查看>>
spring boot
查看>>
核心动画(转场动画和组动画)
查看>>