文档章节

类似ngnix的多进程监听用例

 自由的眼
发布于 2014/11/19 14:14
字数 1226
阅读 2
收藏 0

多进程监听适合于短连接,且连接间无交集的应用。
前两天简单写了一个,在这里保存一下。

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


复制代码



© 著作权归作者所有

粉丝 0
博文 9
码字总数 16565
作品 1
西城
技术主管
私信 提问
NGINX 1.9.1 中的 Socket 切分

原文出处:Nginx 译文出处:OSChina NGINX发布的1.9.1版本引入了一个新的特性:允许使用SOREUSEPORT套接字选项,该选项在许多操作系统的新版本中是可用的,包括DragonFly BSD和Linux(内核版...

Nginx
2016/03/04
0
0
基于Java技术的大型网站架构方案(转)

1、Web层 主体架构可以基于 Struts 1.X/2.X,当然有很多更好的控制层框架供选择,以快速敏捷为准则吧。 抽象出核心库封装 控制器和中间层的操作。 在大规模集群环境下,session复制会引起严重...

指尖的舞者
2012/08/21
391
2
关于Ngnix Apache在一个服务器部署的问题

问题是这样的: 我在一个服务器上同时部署Ngnix,Apache,对外访问都是用域名,请问这样子可以使两个服务都监听在80端口吗? 背景是这样的: 我一直用ngnix做反向代理的服务。现在需要在服务...

qwzh110
2018/07/23
299
3
nginx负载均衡实战

负载均衡的作用:在多个服务器上部署同一个web项目,nginx会将用户的请求随机(可自定义)分发到其中一个web服务器,当其中任意一个或多个web服务器宕机时,不影响用户的正常访问。 基本网络...

疯狂的小潘
2016/02/25
1K
7
Linux-netstat命令小结

netstat命令在面试以及日常开发使用中都会经常出现,所以特地小结一波;首先要知道Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态 ,连接,多播成员等等。 常见参数:...

sssssuuuuu666
2018/03/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

75、GridFS

GridFS是MongoDB提供的用于持久化存储文件的模块,CMS使用Mongo DB存储数据,使用FGridFS可以快速集成开发。 工作原理: 在GridFS存储文件是将文件分块存储,文件会按照256KB的大小分割成多个...

lianbang_W
20分钟前
4
0
js bind 绑定this指向

本文转载于:专业的前端网站➱js bind 绑定this指向 1、示例代码 <!DOCTYPE html><html lang="zh"> <head> <meta charset="UTF-8" /> <title>bind函数绑定this指向......

前端老手
23分钟前
4
0
CentOS Linux 7上将ISO映像文件写成可启动U盘

如今,电脑基本上都支持U盘启动,所以,可以将ISO文件写到U盘上,用来启动并安装操作系统。 我想将一个CentOS Linux 7的ISO映像文件写到U盘上,在CentOS Linux 7操作系统上,执行如下命令: ...

大别阿郎
30分钟前
3
0
深入vue-公司分享ppt

组件注册 全局注册 注册组件,传入一个扩展过的构造器 Vue.component('my-component', Vue.extend({/*...*/})) 注册组件,传入一个选项对象(自动调用Vue.extend) Vue.component('my-comp...

莫西摩西
31分钟前
3
0
gitlab重置管理员密码

登录gitlab服务器 [root@localhost bin]# sudo gitlab-rails console productionLoading production environment (Rails 5.2.3)irb(main):001:0> u = User.where(email: 'admin@example.co......

King华仔o0
41分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部