Linux后台服务端(二)

进程间文件描述符的实现

#include <unistd.h>
#include <sys/types.h>
#include <functional>
#include <memory.h>
#include <sys/socket.h>
class CFunctionBase
{
public:
 virtual ~CFunctionBase() {}
 virtual int operator()() = 0;
};
template<typename _FUNCTION_, typename...
_ARGS_>
class CFunction :public CFunctionBase
{
public:
 CFunction(_FUNCTION_ func, _ARGS_... args)
 :m_binder(std::forward<_FUNCTION_>
(func), std::forward<_ARGS_>(args)...)
 {}
 virtual ~CFunction() {}
 virtual int operator()() {
 return m_binder();
 }
 typename std::_Bindres_helper<int,
_FUNCTION_, _ARGS_...>::type m_binder;
};
class CProcess
{
public:
 CProcess() {
 m_func = NULL;
 memset(pipes, 0, sizeof(pipes));
 }
 ~CProcess() {
 if (m_func != NULL) {
 delete m_func;
 m_func = NULL;
 }
 }
 template<typename _FUNCTION_, typename...
_ARGS_>
 int SetEntryFunction(_FUNCTION_ func,
_ARGS_... args)
 {
 m_func = new CFunction<_FUNCTION_,
_ARGS_...>(func, args...);
 return 0;
 }
 int CreateSubProcess() {
 if (m_func == NULL)return -1;
 int ret = socketpair(AF_LOCAL,
SOCK_STREAM, 0, pipes);
 if (ret == -1)return -2;
 pid_t pid = fork();
 if (pid == -1)return -3;
 if (pid == 0) {
 //子进程
 close(pipes[1]);//关闭掉写
 pipes[1] = 0;
 return (*m_func)();
 }
 //主进程
 close(pipes[0]);
 pipes[0] = 0;
 m_pid = pid;
 return 0;
 }
 int SendFD(int fd) {//主进程完成
 struct msghdr msg;
 iovec iov[2];
 iov[0].iov_base = (char*)"edoyun";
 iov[0].iov_len = 7;
 iov[1].iov_base = (char*)"jueding";
 iov[1].iov_len = 8;
 msg.msg_iov = iov;
 msg.msg_iovlen = 2;
 // 下面的数据,才是我们需要传递的。
 cmsghdr* cmsg = (cmsghdr*)calloc(1,
CMSG_LEN(sizeof(int)));
 if (cmsg == NULL)return -1;
 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
 cmsg->cmsg_level = SOL_SOCKET;
 cmsg->cmsg_type = SCM_RIGHTS;
 *(int*)CMSG_DATA(cmsg) = fd;
 msg.msg_control = cmsg;
 msg.msg_controllen = cmsg->cmsg_len;
 ssize_t ret = sendmsg(pipes[1], &msg,
0);
 free(cmsg);
 if (ret == -1) {
 return -2;
 }
 return 0;
 }
 int RecvFD(int& fd)
 {
 msghdr msg;
 iovec iov[2];
 char buf[][10] = { "","" };
 iov[0].iov_base = buf[0];
 iov[0].iov_len = sizeof(buf[0]);
 iov[1].iov_base = buf[1];
 iov[1].iov_len = sizeof(buf[1]);
 msg.msg_iov = iov;
 msg.msg_iovlen = 2;
 cmsghdr* cmsg = (cmsghdr*)calloc(1,
CMSG_LEN(sizeof(int)));
 if (cmsg == NULL)return -1;
 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
 cmsg->cmsg_level = SOL_SOCKET;
 cmsg->cmsg_type = SCM_RIGHTS;
 msg.msg_control = cmsg;
 msg.msg_controllen =
CMSG_LEN(sizeof(int));
 ssize_t ret = recvmsg(pipes[0], &msg,
0);
 if (ret == -1) {
 free(cmsg);
 return -2;
 }
 fd = *(int*)CMSG_DATA(cmsg);
 return 0;
 }
private:
CFunctionBase* m_func;
 pid_t m_pid;
 int pipes[2];
};

守护进程的实现

守护进程的流程
在这里插入图片描述

守护进程实现代码如下:

static int SwitchDeamon() {
 pid_t ret = fork();
 if (ret == -1)return -1;
 if (ret > 0)exit(0);//主进程到此为止
 //子进程内容如下
 ret = setsid();
 if (ret == -1)return -2;//失败,则返回
 ret = fork();
 if (ret == -1)return -3;
 if (ret > 0)exit(0);//子进程到此为止
 //孙进程的内容如下,进入守护状态
 for (int i = 0; i < 3; i++) close(i);
 umask(0);
 signal(SIGCHLD, SIG_IGN);
 return 0;
 }

日志模块的设计

现在我们一开始就是多进程模式了,所以直接就可以上进程间通
信。
进程间通信,最方便最快速的就是本地套接字通信了。

文件通信磁盘速度慢
管道在多线程环境下不太方便(可能会出现内容插入)而且是单
向的。
信号量信息量太少
内存共享需要反复加锁同步,否则可能出现问题
消息函数(sendmsg、recvmsg)需要创建时确定
网络套接字通信,需要额外的IP和端口

所以本地套接字是最佳选择
无需IP和端口,不影响服务器对外的资源
信息无需加锁,可以多线程并发写
数据传输量巨大,传输速率高(纯内存读写)
日志模块的设计图
在这里插入图片描述

进程间通信的实现

本地套接字的封装
在这里插入图片描述

日志模块的实现

#pragma once
#include "Thread.h"
#include "Socket.h"
#include <list>
#include <sys/timeb.h>
#include <stdarg.h>
#include <sstream>
#include <sys/stat.h>
enum LogLevel {
 LOG_INFO,
 LOG_DEBUG,
 LOG_WARNING,
 LOG_ERROR,
 LOG_FATAL
};
class LogInfo {
public:
 LogInfo(
 const char* file, int line, const char*
func,
 pid_t pid, pthread_t tid, int level,
 const char* fmt, ...);
 LogInfo(
 const char* file, int line, const char*
func,
 pid_t pid, pthread_t tid, int level);
 
 LogInfo(const char* file, int line, const
char* func,
 pid_t pid, pthread_t tid, int level,
 void* pData, size_t nSize);
 
 ~LogInfo();
 operator Buffer()const {
 return m_buf;
 }
 template<typename T>
 LogInfo& operator<<(const T& data) {
 std::stringstream stream;
 stream << data;
 m_buf += stream.str();
 return *this;
 }
private:
 bool bAuto;//默认是false 流式日志,则为true
 Buffer m_buf;
};
class CLoggerServer
{
public:
 CLoggerServer() :
 m_thread(&CLoggerServer::ThreadFunc,
this)
 {
 m_server = NULL;
 m_path = "./log/" + GetTimeStr() +
".log";
 printf("%s(%d):[%s]path=%s\n", __FILE__,
__LINE__, __FUNCTION__, (char*)m_path);
 }
 ~CLoggerServer() {
 Close();
 }
public:
 CLoggerServer(const CLoggerServer&) =
delete;
 CLoggerServer& operator=(const
CLoggerServer&) = delete;
public:
 //日志服务器的启动
 int Start() {
 if (m_server != NULL)return -1;
 if (access("log", W_OK | R_OK) != 0) {
 mkdir("log", S_IRUSR | S_IWUSR |
S_IRGRP | S_IWGRP | S_IROTH);
 }
 m_file = fopen(m_path, "w+");
 if (m_file == NULL)return -2;
 int ret = m_epoll.Create(1);
 if (ret != 0)return -3;
 m_server = new CLocalSocket();
 if (m_server == NULL) {
 Close();
 return -4;
 }
 ret = m_server-
>Init(CSockParam("./log/server.sock",
(int)SOCK_ISSERVER));
 if (ret != 0) {
 Close();
 return -5;
 }
 ret = m_thread.Start();
 if (ret != 0) {
 Close();
 return -6;
 }
 return 0;
 }
 int ThreadFunc() {
 EPEvents events;
 std::map<int, CSocketBase*> mapClients;
 while (m_thread.isValid() && (m_epoll !=
-1) && (m_server != NULL)) {
 ssize_t ret =
m_epoll.WaitEvents(events, 1);
 if (ret < 0)break;
 if (ret > 0) {
 ssize_t i = 0;
 for (; i < ret; i++) {
 if (events[i].events &
EPOLLERR) {
 break;
 }
 else if (events[i].events &
EPOLLIN) {
 if (events[i].data.ptr
== m_server) {
 CSocketBase* pClient
= NULL;
 int r = m_server-
>Link(&pClient);
 if (r < 0) continue;
 r =
m_epoll.Add(*pClient, EpollData((void*)pClient),
EPOLLIN | EPOLLERR);
 if (r < 0) {
 delete pClient;
 continue;
 }
 auto it =
mapClients.find(*pClient);
 if (it->second !=
NULL) {
 delete it-
>second;
 }
 mapClients[*pClient]
= pClient;
 }
 else {
 CSocketBase* pClient
= (CSocketBase*)events[i].data.ptr;
 if (pClient != NULL)
{
 Buffer data(1024
* 1024);
* int r = pClient-
>Recv(data);
 if (r <= 0) {
 delete
pClient;
 
mapClients[*pClient] = NULL;
 }
 else {
 
WriteLog(data);
 }
 }
 }
 }
 }
 if (i != ret) {
 break;
 }
 }
 }
 for (auto it = mapClients.begin(); it !=
mapClients.end(); it++) {
 if (it->second) {
 delete it->second;
 }
 }
 mapClients.clear();
 return 0;
 }
 int Close() {
 if (m_server != NULL) {
 CSocketBase* p = m_server;
 m_server = NULL;
 delete p;
 }
 m_epoll.Close();
 m_thread.Stop();
 return 0;
 }
 //给其他非日志进程的进程和线程使用的
 static void Trace(const LogInfo& info) {
 static thread_local CLocalSocket client;
 if (client == -1) {
 int ret = 0;
 ret =
client.Init(CSockParam("./log/server.sock", 0));
 if (ret != 0) {
#ifdef _DEBUG
 printf("%s(%d):[%s]ret=%d\n",
__FILE__, __LINE__, __FUNCTION__, ret);
#endif
 return;
 }
 }
 client.Send(info);
 }
 static Buffer GetTimeStr() {
 Buffer result(128);
 timeb tmb;
 ftime(&tmb);
 tm* pTm = localtime(&tmb.time);
 int nSize = snprintf(result,
result.size(),
 "%04d-%02d-%02d %02d-%02d-%02d
%03d",
 pTm->tm_year + 1900, pTm->tm_mon +
1, pTm->tm_mday,
 pTm->tm_hour, pTm->tm_min, pTm-
>tm_sec,
 tmb.millitm
 );
 result.resize(nSize);
 return result;
 }
private:
 void WriteLog(const Buffer& data) {
 if (m_file != NULL) {
 FILE* pFile = m_file;
 fwrite((char*)data, 1, data.size(),
pFile);
 fflush(pFile);
#ifdef _DEBUG
 printf("%s", (char*)data);
#endif
 }
 }
private:
 CThread m_thread;
 CEpoll m_epoll;
 CSocketBase* m_server;
 Buffer m_path;
 FILE* m_file;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值