【slighttpd】基于lighttpd架构的Server项目实战(3)—Master&Worker模式

现在,我们开始一步步构建我们的项目了~

Master-Worker模式

本次一共涉及2个类:Master和Worker;

以下是两者的头文件:

/*************************************************************************
    > File Name: server.h
    > Author: Jiange
    > Mail: jiangezh@qq.com 
    > Created Time: 2016年01月27日 星期三 19时33分00秒
 ************************************************************************/

#ifndef _MASTER_H
#define _MASTER_H

#include "worker.h"

#include <string>

#include "event2/event.h"
#include "event2/util.h"

class Master
{
    public:

        Master();
        ~Master();

        bool StartMaster();

        static void MasterExitSignal(evutil_socket_t signo, short event, void *arg); //SIGINT信号回调函数

        static void MasterChldSignal(evutil_socket_t signo, short event, void *arg); //SIGCHLD信号回调函数

        Worker              worker;

        struct event_base  *m_base;
        struct event       *m_exit_event;
        struct event       *m_chld_event;

        int                 nums_of_child;  //子进程个数
};

#endif
/*************************************************************************
    > File Name: worker.h
    > Author: Jiange
    > Mail: jiangezh@qq.com 
    > Created Time: 2016年01月27日 星期三 20时10分35秒
 ************************************************************************/

#ifndef _WORKER_H
#define _WORKER_H

#include <string>
#include <map>

#include "event2/event.h"
#include "event2/util.h"

#include "util.h"

class Master;

class Worker
{
    public:
        Worker();
        ~Worker();

        void Run();

        static void WorkerExitSignal(evutil_socket_t signo, short event, void *arg);

        Master             *master;

        struct event_base  *w_base;
        struct event       *w_exit_event;

        std::string         s_inbuf;
        std::string         s_intmp;
        std::string         s_outbuf;

};

#endif

具体实现:

/*************************************************************************
    > File Name: master.cpp
    > Author: Jiange
    > Mail: jiangezh@qq.com 
    > Created Time: 2016年01月27日 星期三 19时37分23秒
 ************************************************************************/

#include "master.h"
#include "worker.h"

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <iostream>

Master::Master()
{
    m_base = NULL;
    m_exit_event  = NULL;
    m_chld_event  = NULL;
    nums_of_child = 4; //4个子进程
}

Master::~Master()
{
    if (m_base)
    {
        event_free(m_exit_event);
        event_free(m_chld_event);
        event_base_free(m_base);
    }
    std::cout << "Master Closed" << std::endl;
}


bool Master::StartMaster()
{
    std::cout << "Start Master" << std::endl;
    worker.master = this;
    //创建一定数量的worker
    while (nums_of_child > 0)
    {
        switch (fork())
        {
            case -1:
                return false;
            case 0:
            {
                worker.Run(); //worker子进程入口
                return true;
            }   
            default:
                --nums_of_child;
                break;
        }
    }

    //Master监听信号,一个用于退出,一个用于处理结束的子进程
    m_base = event_base_new(); 
    m_exit_event = evsignal_new(m_base, SIGINT, Master::MasterExitSignal, m_base);
    m_chld_event = evsignal_new(m_base, SIGCHLD, Master::MasterChldSignal, this);
    evsignal_add(m_exit_event, NULL);
    evsignal_add(m_chld_event, NULL);

    //开始事件循环
    event_base_dispatch(m_base);
    return true;
}

void Master::MasterExitSignal(evutil_socket_t signo, short event, void *arg)
{   
    //通知所有子进程。暂时不需要,因为程序不是守护进程。
    //所有子进程都跟终端关联,都会收到SIGINT
    //kill(0, SIGINT);

    //结束事件循环
    event_base_loopexit((struct event_base*)arg, NULL);
}

//防止子进程僵死,使用waitpid而不是wait->可能多个子进程同时关闭
void Master::MasterChldSignal(evutil_socket_t signo, short event, void *arg)
{   
    Master *master = (Master *)arg;
    pid_t   pid;
    int     stat;
    while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
    {
        ++(master->nums_of_child);
        std::cout << "Child " << pid << " terminated" << std::endl;
    }
}
/*************************************************************************
    > File Name: worker.cpp
    > Author: Jiange
    > Mail: jiangezh@qq.com 
    > Created Time: 2016年01月28日 星期四 12时06分22秒
 ************************************************************************/

#include "worker.h"
#include "master.h"

#include <stdlib.h>
#include <iostream>

Worker::Worker()
{
    master          = NULL;
    w_base          = NULL;
    w_exit_event    = NULL;
}

Worker::~Worker()
{
    if (w_exit_event)
        event_free(w_exit_event);

    if (w_base)
        event_base_free(w_base);

    std::cout << "Worker closed" << std::endl;
}

void Worker::Run()
{
    w_base = event_base_new();
    w_exit_event = evsignal_new(w_base, SIGINT, Worker::WorkerExitSignal, w_base);
    evsignal_add(w_exit_event, NULL);

    event_base_dispatch(w_base);
    return;
}

void Worker::WorkerExitSignal(evutil_socket_t signo, short event, void *arg)
{   
    event_base_loopexit((struct event_base*)arg, NULL);
}

这样子,一个简单的“Master-Worker模式”就完成了。

测试入口:

/*************************************************************************
    > File Name: main.cpp
    > Author: Jiange
    > Mail: jiangezh@qq.com 
    > Created Time: 2016年01月27日 星期三 19时29分26秒
 ************************************************************************/

#include "master.h"

#include <iostream>

int main(int argc, char * argv[])
{
    Master master;
    std::cout << "----Slighttpd----" << std::endl;
    if (!master.StartMaster())
        return -1;
    std::cout << "----Goodbye----" << std::endl;
    return 0;
}

需要注意的几个点:

  1. Master和Worker所做的事情是不同的,因此两者均有自己独立的event_base;

  2. worker的event_base_new()需要在run()函数中使用(在fork之后),而不能在构造函数中初始化时分配(fork之前)。否则,好像4个子进程将共用同一个event_base。(Q:按理来说fork应该是完全复制过来的,为什么会共用同一个呢?可能是跟libevent的实现方式有关?)

接下来,我们需要对它进行拓展,以后将在Master中加入插件相关的内容,在Worker中加入监听者Listener和连接者Connection。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值