1. 程式人生 > >【slighttpd】基於lighttpd架構的Server專案實戰(3)—Master&Worker模式

【slighttpd】基於lighttpd架構的Server專案實戰(3)—Master&Worker模式

轉載地址:https://blog.csdn.net/jiange_zh/article/details/50636180

現在,我們開始一步步構建我們的專案了~

Master-Worker模式

本次一共涉及2個類:Master和Worker;

以下是兩者的標頭檔案:

/*************************************************************************
    > File Name: server.h
    > Author: Jiange
    > Mail: [email protected]
> 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); 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: [email protected] 
    > 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: [email protected] 
    > 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: [email protected] 
    > 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: [email protected] 
    > 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。