类似ngnix的多进程监听用例
2019独角兽企业重金招聘Python工程师标准>>>
多进程监听适合于短连接,且连接间无交集的应用。
前两天简单写了一个,在这里保存一下。
#include <sys/types.h>
#include <stdarg.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
char * ToDateStr(time_t tt, char *szDateTime, const char *szFormat)
{
size_t i, len;
char field[3], c1 = ' ', c2 = '-', c3 = ':', c4 = '/'; /* 常见的分隔符 */
char *p;
struct tm result;
if (szDateTime == NULL)
{
return NULL;
}
localtime_r(&tt, &result);
/* 默认的格式 yyyy-mm-dd hh:mi:ss*/
if (szFormat == NULL)
{
sprintf(szDateTime, "%04d-%02d-%02d %02d:%02d:%02d",
result.tm_year + 1900, result.tm_mon + 1, result.tm_mday,
result.tm_hour, result.tm_min, result.tm_sec);
szDateTime[strlen("yyyy-mm-dd hh:mi:ss")] = '\0';
return szDateTime;
}
/* 用户指定格式 */
len = strlen(szFormat);
i = 0;
p = szDateTime;
/* 判断前4个字符是否为yyyy */
if (strncmp(szFormat, "yyyy", 4) == 0)
{
sprintf(p, "%04d", result.tm_year + 1900);
p += 4;
i += 4;
}
/* 格式中的剩余部分 */
while (i < len)
{
/* 格式中的每个域必须以两个紧邻字符为整体 */
field[0] = szFormat[i];
i += 1;
if (field[0] != c1 && field[0] != c2 && field[0] != c3 && field[0] != c4) /* 如果第一个字符不是分隔符 */
{
field[1] = szFormat[i];
field[2] = '\0';
i += 1;
if (strcmp(field, "yy") == 0) /* 这种情况下整个格式里最多有两个yy */
{
sprintf(p, "%02d", (result.tm_year + 1900) % 100);
}
else if (strcmp(field, "mm") == 0)
{
sprintf(p, "%02d", result.tm_mon + 1);
}
else if (strcmp(field, "dd") == 0)
{
sprintf(p, "%02d", result.tm_mday);
}
else if (strcmp(field, "hh") == 0)
{
sprintf(p, "%02d", result.tm_hour);
}
else if (strcmp(field, "mi") == 0)
{
sprintf(p, "%02d", result.tm_min);
}
else if (strcmp(field, "ss") == 0)
{
sprintf(p, "%02d", result.tm_sec);
}
else
{
return NULL;
}
p += 2;
}
else /* 如果是分隔符则直接打印出来 */
{
*p = field[0];
p += 1;
}
}
*p = '\0';
return szDateTime;
}
//时间格式化
char * Now(char *szDateTime, const char *szFormat)
{
return ToDateStr(time(NULL), szDateTime, szFormat);
}
//写日志文件
void mlog(char *logFileName,char *fmt,...)
{
char log_path[128];
char date_time[20];
char date_str[10];
char time_str[10];
FILE *fp;
va_list varArg;
char buf_str[1024];
memset(log_path, 0, sizeof(log_path));
memset(date_time, 0, sizeof(date_time));
memset(date_str, 0, sizeof(date_str));
memset(time_str, 0, sizeof(time_str));
memset(buf_str, 0, sizeof(buf_str));
// 取日期及时间
Now(date_time, "yyyymmddhh:mi:ss");
memcpy(date_str, date_time, 8);
memcpy(time_str, date_time + 8, 8);
/* 组合日志文件目录 */
sprintf(log_path, "./%s.%s", logFileName, date_str);
/* 以(创建)追加方式打开日志文件 */
fp = fopen(log_path, "a+");
if(fp == NULL)
{
return;
}
va_start(varArg, fmt);
vsprintf(buf_str, fmt, varArg);
va_end(varArg);
fprintf(fp, "%s: %s\n", time_str, buf_str);
fclose(fp);
}
//写独占文件锁
int AcquireWriteLock(int fd, int start, int len)
{
struct flock arg;
arg.l_type = F_WRLCK; // 加写锁
arg.l_whence = SEEK_SET;
arg.l_start = start;
arg.l_len = len;
arg.l_pid = getpid();
return fcntl(fd, F_SETLKW, &arg);
}
//释放独占文件锁
int ReleaseLock(int fd, int start, int len)
{
struct flock arg;
arg.l_type = F_UNLCK; // 解锁
arg.l_whence = SEEK_SET;
arg.l_start = start;
arg.l_len = len;
arg.l_pid = getpid();
return fcntl(fd, F_SETLKW, &arg);
}
//查看写锁
int SeeLock(int fd, int start, int len)
{
struct flock arg;
arg.l_type = F_WRLCK;
arg.l_whence = SEEK_SET;
arg.l_start = start;
arg.l_len = len;
arg.l_pid = getpid();
if (fcntl(fd, F_GETLK, &arg) != 0) // 获取锁
{
return -1; // 测试失败
}
if (arg.l_type == F_UNLCK)
{
return 0; // 无锁
}
else if (arg.l_type == F_RDLCK)
{
return 1; // 读锁
}
else if (arg.l_type == F_WRLCK)
{
return 2; // 写所
}
return 0;
}
int Chlid_Run(int nServerfd)
{
socklen_t nClientAddrSize = 0;
int nClientfd = -1;
struct sockaddr_in Clientaddr;
//循环监听接收数据
while(1)
{
nClientAddrSize = sizeof(struct sockaddr_in);
nClientfd = accept(nServerfd, (struct sockaddr *)(&Clientaddr), &nClientAddrSize);
if(-1 == nClientfd)
{
printf("[Chlid_Run]accept fail !\n");
return -1;
}
//随便返回一个数据
char szReturn[20];
sprintf(szReturn, "hello");
if(-1 == write(nClientfd, szReturn, strlen(szReturn)))
{
mlog((char* )"process", (char* )"[Chlid_Run](%s:%d)(%d)Connected Send error!", inet_ntoa(Clientaddr.sin_addr), ntohs(Clientaddr.sin_port), getpid());
return -1;
}
//打印进程ID
mlog((char* )"process", (char* )"[Chlid_Run](%s:%d)Connected pid=%d!", inet_ntoa(Clientaddr.sin_addr), ntohs(Clientaddr.sin_port), getpid());
//关闭socket连接
close(nClientfd);
}
}
int main(int argc, char *argv[])
{
//当前监控子线程个数
int nNumChlid = 5;
//检测时间间隔参数
struct timespec tsRqt;
//文件锁
int fd_lock = 0;
//要监听的IP和端口
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int nPort = 10030; //监听端口
int nServerfd = 0; //Server Socket
int nRet = 0;
//主进程检测时间间隔(设置每隔5秒一次)
tsRqt.tv_sec = 5;
tsRqt.tv_nsec = 0;
// 打开(创建)锁文件
char szFileName[200] = {'\0'};
memset(szFileName, 0, sizeof(flock));
sprintf(szFileName, "./MultiListen.lk", getenv("HOME"));
fd_lock = open(szFileName, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
if (fd_lock < 0)
{
printf("open the flock and exit, errno = %d.", errno);
exit(1);
}
//查看当前文件锁是否已锁
nRet = SeeLock(fd_lock, 0, sizeof(int));
if (nRet == -1 || nRet == 2)
{
printf("file is already exist!");
exit(1);
}
//如果文件锁没锁,则锁住当前文件锁
if (AcquireWriteLock(fd_lock, 0, sizeof(int)) != 0)
{
printf("lock the file failure and exit, idx = 0!.");
exit(1);
}
//写入子进程锁信息
lseek(fd_lock, 0, SEEK_SET);
for (int nIndex = 0; nIndex <= nNumChlid; nIndex++)
{
write(fd_lock, &nIndex, sizeof(nIndex));
}
//在这里初始化监听
nServerfd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == nServerfd)
{
printf("[Main]Create Server FD error.\n");
return -1;
}
//初始化监听地址信息
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY); /* 这里地址使用全0,即所有 */
server_addr.sin_port=htons(nPort);
//绑定Socket FD
if(-1 == bind(nServerfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)))
{
printf("[main]bind server addr fail!\n");
return -1;
}
//开始监听
if(-1 == listen(nServerfd, 5))
{
printf("[main]listen server fail!\r\n");
return -1;
}
while (1)
{
for (int nChlidIndex = 1; nChlidIndex <= nNumChlid; nChlidIndex++)
{
//测试每个子进程的锁是否还存在
nRet = SeeLock(fd_lock, nChlidIndex * sizeof(int), sizeof(int));
if (nRet == -1 || nRet == 2)
{
continue;
}
//如果文件锁没有被锁,则设置文件锁,并启动子进程
int npid = fork();
if (npid == 0)
{
//上文件锁
if(AcquireWriteLock(fd_lock, nChlidIndex * sizeof(int), sizeof(int)) != 0)
{
printf("child %d AcquireWriteLock failure.\n", nChlidIndex);
exit(1);
}
//启动子进程
Chlid_Run(nServerfd);
//子进程在执行完任务后必须退出循环和释放锁
//ReleaseLock(fd_lock, nChlidIndex * sizeof(int), sizeof(int));
}
}
printf("child count(%d) is ok.\n", nNumChlid);
//检查间隔
nanosleep(&tsRqt, NULL);
}
return 0;
}
复制代码
转载于:https://my.oschina.net/u/2273582/blog/346311
类似ngnix的多进程监听用例相关推荐
- Cocos Creator_实现策略_多点触控之触控管理器监听单例_TypeScript
触控管理器(TypeScript实现) [主要功能] 1.实时访问每个触摸手指的状态(手指顺序,touch位置,按钮状态,Touch类) 2.使鼠标与触摸的API兼容访问 3.实时访问键盘按钮状态 4 ...
- php进程监听是什么意思,多进程监听同个端口及单进程监听多个端口的php版本实现...
最近在看nginx设计原理时思考到两个问题,便是: 多个进程能否监听同个端口? 单个进程能否监听多个端口? 当然随着学习的深入,答案均是肯定的,在这个过程中笔者为了验证,用php写了两个例子,在这里分 ...
- oracle未获得监听器,无监听文件listener.ora的动态监听小例试验
在数据库服务器上,监听文件的位置是:$ORACLE_HOME/network/admin/listener.ora 试验如下: 移动db服务器上的监听文件,如下命令: [oracle@ENMOEDU ...
- epoll监听文件_【原创】万字长文浅析:Epoll与Java Nio的那些事儿
" Epoll 是Linux内核的高性能.可扩展的I/O事件通知机制. 在linux2.5.44首次引入epoll,它设计的目的旨在取代既有的select.poll系统函数,让需要大量操作文 ...
- 如何多个进程监听同一个端口
1. 问题描述 一个进程监听端口,经验告诉我们,如果多次启动一个进程会报错:"Address already in use!".这是由于bind函数导致的,由于该端口号已经被第一个 ...
- 【京东个人中心】——Nodejs/Ajax/HTML5/Mysql爬坑之注册与登录监听
一.引言 在数据库和静态页面都创建好之后,下面就该接着完成后台Node.js监听注册和登录的部分了.这个部分主要使用的技术是:Node.js的Express框架和ajax异步请求.登录和注册的代码实现 ...
- Linux中不同进程同一个端口,linux系统实现多个进程监听同一个端口
通过 fork 创建子进程的方式可以实现父子进程监听相同的端口. 方法:在绑定端口号(bind函数)之后,监听端口号之前(listen函数),用fork()函数生成子进程,这样子进程就可以克隆父进程, ...
- python多进程关闭socket_用Python制作一个多进程UDP服务器,一个进程监听一个p
我想用Python制作一个多进程UDP服务器,从一个类中为每个进程监听一个端口: processListener.py:import multiprocessing import socket cla ...
- java 观察者模式_重学 Java 设计模式:实战观察者模式「模拟类似小客车指标摇号过程,监听消息通知用户中签场景」...
一.前言 知道的越多不知道的就越多 编程开发这条路上的知识是无穷无尽的,就像以前你敢说精通Java,到后来学到越来越多只想写了解Java,过了几年现在可能想说懂一点点Java.当视野和格局的扩大,会让 ...
最新文章
- 从零入门 Serverless | 一文搞懂函数计算及其工作原理
- 如何使PING命令带上日期,做长久的跟踪
- php浏览器头部获取,如何获取PHP以显示从浏览器收到的标头?
- minio分布式集群示例: 4节点,每节点4块盘
- html5实现的复古软件winamp的播放效果
- ue4打包问题的巧妙解决——二分回退大法!
- Easy RealMedia Producer使用向导
- 用python做计算器(超级版)
- 小米笔记本网卡驱动失效,无法联网
- 科学家用Google Earth发现千年古迹
- java jdk jre版本要一样吗a_JDK是什么?JRE是什么?JDK和JRE的区别?
- CCA(典型相关分析)
- Httpclient4 简介
- iOS开发初学者入门需要学习哪些知识?
- php下一页的代码,php 下一页的代码
- 微商做引流产品怎么做效果更好?为什么他人的生意这么好而自己没有生意呢?
- HMS华为账号登入全部流程加详解流程机制
- 如何查看Tomcat是否安装配置成功
- python怎么打开qq_Python怎么登录QQ空间?
- 【小甲鱼C语言】课后笔记第一章第二节——变量
热门文章
- 卡巴循环30天不限次数循环试用工具
- Swift学习: 从Objective-C到Swift
- Windows下搭建PHP开发环境
- cinder存储服务
- 正确生成浮点型的方法,解决sqlachemy Float浮点型的坑,生成float类型时,长度和精度均为0,导致查询不到结果!...
- Centos7 下 配置 rsync 以及 rsync+inotify 实时同步
- 你有没有试过“闭上眼”使用:京东、滴滴、QQ、支付宝?
- 如何设置 Linux 上 SSH 登录的 Email 提醒
- 微软批量授权版WINDOWS 10资料(截至到2015年11月,此处无下载地址)
- 提高性能的Varnish缓存方案