|
多进程监听适合于短连接,且连接间无交集的应用。
前两天简单写了一个,在这里保存一下。- #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;
- }
复制代码
|
|