国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【基于C++HTTP 服務(wù)器的epoll 改造】

這篇具有很好參考價(jià)值的文章主要介紹了【基于C++HTTP 服務(wù)器的epoll 改造】。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

打印模塊

Log.hpp 方便使用

#pragma once

#include <iostream>
#include <string>
#include <ctime>

#define INFO    1
#define WARNING 2
#define ERROR   3
#define FATAL   4

#define LOG(level, message) Log(#level, message, __FILE__, __LINE__)

void Log(std::string level, std::string message, std::string file_name, int line)
{
    std::cout<<"["<<level<<"]["<<time(nullptr)<<"]["<<message<<"]["<<file_name<<"]["<<line<<"]"<<std::endl;
}

TcpServer.hpp

#pragma once

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "Log.hpp"

#define BACKLOG 5

class TcpServer{
    private:
        int _port; //端口號(hào)
        int _listen_sock; //監(jiān)聽(tīng)套接字
        static TcpServer* _svr;
        int epollfd;
    private:
        TcpServer(int port)
            :_port(port)
            ,_listen_sock(-1)
        {}
        TcpServer(const TcpServer&)
        {}
    public:
        static TcpServer* GetInstance(int port)
        {
            static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
            if(_svr == nullptr){
                pthread_mutex_lock(&lock);
                if(_svr == nullptr){
                    _svr = new TcpServer(port);
                    _svr->InitServer();
                }
                pthread_mutex_unlock(&lock);
            }
            return _svr;
        }
        void InitServer()
        {
            Socket();
            Bind();
            Listen();
            LOG(INFO, "tcp_server init ... success");
        }
        void Socket()
        {
            _listen_sock = socket(AF_INET, SOCK_STREAM, 0);
            if(_listen_sock < 0){
                LOG(FATAL, "socket error!");
                exit(1);
            }
            int opt = 1;
            setsockopt(_listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
            LOG(INFO, "create socket ... success");
        }
        void Bind()
        {
            struct sockaddr_in local;
            memset(&local, 0, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);
            local.sin_addr.s_addr = INADDR_ANY; //云服務(wù)器不能直接綁定公網(wǎng)IP
            if(bind(_listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0){
                LOG(FATAL, "bind error!");
                exit(2);
            }
            LOG(INFO, "bind socket ... success");
        }
        void Listen()
        {
            if(listen(_listen_sock, BACKLOG) < 0){
                LOG(FATAL, "listen error!");
                exit(3);
            }
            LOG(INFO, "listen socket ... success");
        }
        int Sock()
        {
            return _listen_sock;
        }
        ~TcpServer()
        {
            if(_listen_sock >= 0){
                close(_listen_sock);
            }
        }
};
TcpServer* TcpServer::_svr = nullptr;

HttpServer.hpp

#pragma once

#include <iostream>
#include <sys/epoll.h>
#include <signal.h>
#include "TcpServer.hpp"
#include "Task.hpp"
#include "ThreadPool.hpp"
#include "Log.hpp"

#define PORT 8081

#define MAX_EVENT_NUMBER 1024

class HttpServer{
    private:
        int _port;
        bool _stop;
        int epollfd;
				struct epoll_event events[MAX_EVENT_NUMBER];
    public:
        HttpServer(int port)
            :_port(port)
        {
        	  _stop = false;
        		epollfd = -1;
        }
	      void InitServer()
	      {
	          signal(SIGPIPE, SIG_IGN); //忽略SIGPIPE信號(hào),防止寫入時(shí)崩潰
	      }

		
		int setnonblocking(int fd)
		{
			int option = fcntl(fd, F_GETFL) |  O_NONBLOCK;
			fcntl(fd, F_SETFD, option);
			return fcntl(fd, F_GETFL);
		}

		void addfd(int fd, bool enable_et){
			struct epoll_event ev;
			ev.data.fd = fd;
			ev.events = EPOLLIN;
			if(enable_et){
				ev.events |= EPOLLET;
			}
			epoll_ctl(this->epollfd, EPOLL_CTL_ADD, fd, &ev);
			setnonblocking(fd);
		}
  
        void work(int nread, int listenfd)
        {
              for(int i = 0; i < nread; i++)
              {
                int sockfd = events[i].data.fd;
                if(sockfd == listenfd){
                    struct sockaddr_in peer;
                    memset(&peer, 0, sizeof(peer));
                    socklen_t len = sizeof(peer);
                    int connfd = accept(listenfd, (struct sockaddr*)&peer, &len);
                    addfd(connfd, true);
                }else if(events[i].events &  EPOLLIN){
                    LOG(INFO, "event trigger once");
                    LOG(INFO, "get a new link");
                    Task task(sockfd);
                    ThreadPool::GetInstance()->PushTask(task);   
                }else{
                    LOG(INFO, "something else happened");
                }
              }  
        }

        void Loop()
        {
            LOG(INFO, "loop begin");
            TcpServer* tsvr = TcpServer::GetInstance(_port);
            int listen_sock = tsvr->Sock();
            epollfd = epoll_create(5);
						addfd(listen_sock, true);
            while(!_stop){

                int nread = epoll_wait(this->epollfd, events, MAX_EVENT_NUMBER, -1);
                if(nread < 0){
                    continue;
                }
                // struct sockaddr_in peer;
                // memset(&peer, 0, sizeof(peer));
                // socklen_t len = sizeof(peer);
                // int sock = accept(listen_sock, (struct sockaddr*)&peer, &len);
                // if(sock < 0){
                //     continue;
                // }
                // LOG(INFO, "get a new link");
                // Task task(sock);
                // ThreadPool::GetInstance()->PushTask(task);
                //lt(nread, listen_sock);
                work(nread, listen_sock);

                //int* p = new int(sock);
                //pthread_t tid;
                //pthread_create(&tid, nullptr, Entrance::HandlerRequest, (void*)p);
                //pthread_detach(tid);
            }
        }
        ~HttpServer()
        {}
};

Task.hpp

#pragma once

#include <iostream>
#include <unistd.h>
#include "Protocol.hpp"

class Task{
    private:
        int _sock;
        CallBack _handler; //回調(diào)
    public:
        Task()
        {}
        Task(int sock)
            :_sock(sock)
        {}
        //處理任務(wù)
        void ProcessOn()
        {
            _handler(_sock); //調(diào)用CallBack的仿函數(shù)
        }
        ~Task()
        {}
};

ThreadPool.hpp

#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>
#include "Task.hpp"
#include "Log.hpp"

#define NUM 6

class ThreadPool{
    private:
        std::queue<Task> _task_queue; //任務(wù)隊(duì)列
        int _num;
        bool _stop;
        pthread_mutex_t _mutex;
        pthread_cond_t _cond;
        static ThreadPool* _inst;
    private:
        //構(gòu)造函數(shù)私有
        ThreadPool(int num = NUM)
            :_num(num)
            ,_stop(false)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_cond, nullptr);
        }
        //拷貝構(gòu)造函數(shù)私有或刪除
        ThreadPool(const ThreadPool&)=delete;

        bool IsEmpty()
        {
            return _task_queue.empty();
        }
        bool IsStop()
        {
            return _stop;
        }
        void LockQueue()
        {
            pthread_mutex_lock(&_mutex);
        }
        void UnLockQueue()
        {
            pthread_mutex_unlock(&_mutex);
        }
        void ThreadWait()
        {
            pthread_cond_wait(&_cond, &_mutex);
        }
        void ThreadWakeUp()
        {
            pthread_cond_signal(&_cond);
        }
    public:
        static ThreadPool* GetInstance()
        {
            static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
            if(_inst == nullptr){
                pthread_mutex_lock(&mtx);
                if(_inst == nullptr){
                    _inst = new ThreadPool();
                    _inst->InitThreadPool();
                }
                pthread_mutex_unlock(&mtx);
            }
            return _inst;
        }
        static void* ThreadRoutine(void* arg)
        {
            pthread_detach(pthread_self());
            ThreadPool* tp = (ThreadPool*)arg;
            while(true){
                tp->LockQueue();
                while(tp->IsEmpty()){
                    tp->ThreadWait();
                }
                Task task;
                tp->PopTask(task);
                tp->UnLockQueue();

                task.ProcessOn(); //處理任務(wù)
            }
        }
        bool InitThreadPool()
        {
            pthread_t tid;
            for(int i = 0;i < _num;i++){
                if(pthread_create(&tid, nullptr, ThreadRoutine, this) != 0){
                    LOG(FATAL, "create thread pool error!");
                    return false;
                }
            }
            LOG(INFO, "create thread pool success!");
            return true;
        }
        void PushTask(const Task& task)
        {
            LockQueue();
            _task_queue.push(task);
            UnLockQueue();
            ThreadWakeUp();
        }
        void PopTask(Task& task)
        {
            task = _task_queue.front();
            _task_queue.pop();
        }
        ~ThreadPool()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }
};
ThreadPool* ThreadPool::_inst = nullptr;

Util.hpp

#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>

//工具類
class Util{
    public:
        static int ReadLine(int sock, std::string& out)
        {
            char ch = 'X'; //隨便設(shè)置一個(gè)字符,只要不是\n即可
            while(ch != '\n'){
                ssize_t size = recv(sock, &ch, 1, 0);
                if(size > 0){
                    if(ch == '\r'){
                        //窺探
                        recv(sock, &ch, 1, MSG_PEEK);
                        if(ch == '\n'){
                            //窺探成功
                            //\r\n->\n
                            recv(sock, &ch, 1, 0);
                        }
                        else{
                            //\r->\n
                            ch = '\n';
                        }
                    }
                    //普通字符或\n
                    out.push_back(ch);
                }
                else if(size == 0){
                    return 0;
                }
                else{
                    return -1;
                }
            }
            return out.size();
        }
        static bool CutString(std::string& target, std::string& sub1_out, std::string& sub2_out, std::string sep)
        {
            size_t pos = target.find(sep, 0);
            if(pos != std::string::npos){
                sub1_out = target.substr(0, pos);
                sub2_out = target.substr(pos + sep.size());
                return true;
            }
            return false;
        }
};

Protocol.hpp

#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <sstream>
#include <algorithm>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <sys/wait.h>
#include <fcntl.h>
#include "Util.hpp"
#include "Log.hpp"

#define SEP ": "
#define WEB_ROOT "wwwroot"
#define HOME_PAGE "index.html"
#define HTTP_VERSION "HTTP/1.0"
#define LINE_END "\r\n"
#define PAGE_400 "400.html"
#define PAGE_404 "404.html"
#define PAGE_500 "500.html"

#define OK 200
#define BAD_REQUEST 400
#define NOT_FOUND 404
#define SERVER_ERROR 500

static std::string CodeToDesc(int code)
{
    std::string desc;
    switch(code){
        case 200:
            desc = "OK";
            break;
        case 404:
            desc = "Not Found";
            break;
        default:
            break;
    }
    return desc;
}
static std::string SuffixToDesc(const std::string& suffix)
{
    static std::unordered_map<std::string, std::string> suffix_to_desc = {
        {".html", "text/html"},
        {".css", "text/css"},
        {".js", "application/x-javascript"},
        {".jpg", "application/x-jpg"},
        {".xml", "text/xml"}
    };
    auto iter = suffix_to_desc.find(suffix);
    if(iter != suffix_to_desc.end()){
        return iter->second;
    }
    return "text/html";
}

class HttpRequest{
    public:
        std::string _request_line; //請(qǐng)求行
        std::vector<std::string> _request_header; //請(qǐng)求報(bào)頭
        std::string _blank; //空行
        std::string _request_body; //請(qǐng)求正文

        //解析完畢之后的結(jié)果
        std::string _method; //請(qǐng)求方法
        std::string _uri; //URI
        std::string _version; //版本號(hào)

        std::unordered_map<std::string, std::string> _header_kv; //請(qǐng)求報(bào)頭中的鍵值對(duì)
        int _content_length; //正文長(zhǎng)度
        std::string _path; //請(qǐng)求資源的路徑
        std::string _query_string; //uri中攜帶的參數(shù)
        bool _cgi; //是否需要使用CGI模式
    public:
        HttpRequest()
            :_content_length(0)
            ,_cgi(false)
        {}
        ~HttpRequest()
        {}
};

class HttpResponse{
    public:
        std::string _status_line; //狀態(tài)行
        std::vector<std::string> _response_header; //響應(yīng)報(bào)頭
        std::string _blank; //空行
        std::string _response_body; //響應(yīng)正文

        int _status_code; //狀態(tài)碼
        int _fd; //響應(yīng)的文件
        int _size; //響應(yīng)文件的大小
        std::string _suffix; //響應(yīng)文件的后綴
    public:
        HttpResponse()
            :_blank(LINE_END)
            ,_status_code(OK)
            ,_fd(-1)
            ,_size(0)
        {}
        ~HttpResponse()
        {}
};

//讀取請(qǐng)求、分析請(qǐng)求、構(gòu)建響應(yīng)
//IO通信
class EndPoint{
    private:
        int _sock;
        HttpRequest _http_request;
        HttpResponse _http_response;
        bool _stop;
    private:
        //讀取請(qǐng)求行
        bool RecvHttpRequestLine()
        {
            auto& line = _http_request._request_line;
            if(Util::ReadLine(_sock, line) > 0){
                line.resize(line.size() - 1);
                LOG(INFO, line);
            }
            else{
                _stop = true; //讀取出錯(cuò),不予處理
            }
            return _stop;
        }
        //讀取請(qǐng)求報(bào)頭和空行
        bool RecvHttpRequestHeader()
        {
            std::string line;
            while(true){
                line.clear(); //每次讀取之前清空l(shuí)ine
                if(Util::ReadLine(_sock, line) <= 0){
                    _stop = true;
                    break;
                }
                if(line == "\n"){
                    _http_request._blank = line;
                    break;
                }
                line.resize(line.size() - 1);
                _http_request._request_header.push_back(line);
                //LOG(INFO, line);
            }
            return _stop;
        }
        //解析請(qǐng)求行
        void ParseHttpRequestLine()
        {
            auto& line = _http_request._request_line;
            std::stringstream ss(line);
            ss>>_http_request._method>>_http_request._uri>>_http_request._version;
            auto& method = _http_request._method;
            std::transform(method.begin(), method.end(), method.begin(), toupper);
        }
        //解析請(qǐng)求報(bào)頭
        void ParseHttpRequestHeader()
        {
            std::string key;
            std::string value;
            for(auto& iter : _http_request._request_header){
                if(Util::CutString(iter, key, value, SEP))
                {
                    _http_request._header_kv.insert({key, value});
                }
            }
        }
        //判定是否需要讀取請(qǐng)求正文
        bool IsNeedRecvHttpRequestBody()
        {
            auto& method = _http_request._method;
            if(method == "POST"){
                auto& header_kv = _http_request._header_kv;
                auto iter = header_kv.find("Content-Length");
                if(iter != header_kv.end()){
                    _http_request._content_length = atoi(iter->second.c_str());
                    return true;
                }
            }
            return false;
        }
        //讀取請(qǐng)求正文
        bool RecvHttpRequestBody()
        {
            if(IsNeedRecvHttpRequestBody()){
                int content_length = _http_request._content_length;
                auto& body = _http_request._request_body;

                char ch = 0;
                while(content_length){
                    ssize_t size = recv(_sock, &ch, 1, 0);
                    if(size > 0){
                        body.push_back(ch);
                        content_length--;
                    }
                    else{
                        _stop = true;
                        break;
                    }
                }
            }
            return _stop;
        }
        //CGI處理
        int ProcessCgi()
        {
            int code = OK;

            auto& bin = _http_request._path; //要讓子進(jìn)程執(zhí)行的目標(biāo)程序
            auto& method = _http_request._method;
            //父進(jìn)程的數(shù)據(jù)
            auto& query_string = _http_request._query_string; //GET
            auto& request_body = _http_request._request_body; //POST
            int content_length = _http_request._content_length;
            auto& response_body = _http_response._response_body;

            //站在父進(jìn)程角度
            int input[2];
            int output[2];
            if(pipe(input) < 0){
                LOG(ERROR, "pipe input error!");
                code = SERVER_ERROR;
                return code;
            }
            if(pipe(output) < 0){
                LOG(ERROR, "pipe output error!");
                code = SERVER_ERROR;
                return code;
            }

            pid_t pid = fork();
            if(pid == 0){ //child
                close(input[0]);
                close(output[1]);

                //將請(qǐng)求方法通過(guò)環(huán)境變量傳參
                std::string method_env = "METHOD=";
                method_env += method;
                putenv((char*)method_env.c_str());

                if(method == "GET"){ //通過(guò)環(huán)境變量傳參
                    std::string query_env = "QUERY_STRING=";
                    query_env += query_string;
                    putenv((char*)query_env.c_str());
                    LOG(INFO, "GET Method, Add Query_String env");
                }
                else if(method == "POST"){ //導(dǎo)入正文參數(shù)長(zhǎng)度
                    std::string content_length_env = "CONTENT_LENGTH=";
                    content_length_env += std::to_string(content_length);
                    putenv((char*)content_length_env.c_str());
                    LOG(INFO, "POST Method, Add Content_Length env");
                }
                else{
                    //Do Nothing
                }

                dup2(output[0], 0);
                dup2(input[1], 1);

                execl(bin.c_str(), bin.c_str(), nullptr);
                exit(1);
            }
            else if(pid < 0){
                LOG(ERROR, "fork error!");
                code = SERVER_ERROR;
                return code;
            }
            else{ //father
                close(input[1]);
                close(output[0]);
                if(method == "POST"){ //將數(shù)據(jù)寫入到管道當(dāng)中
                    const char* start = request_body.c_str();
                    int total = 0;
                    int size = 0;
                    while(total < content_length && (size = write(output[1], start + total, request_body.size() - total)) > 0){
                        total += size;
                    }
                }
                //std::string test_string = "2021dragon";
                //send(output[1], test_string.c_str(), test_string.size(), 0);
                
                char ch = 0;
                while(read(input[0], &ch, 1) > 0){
                    response_body.push_back(ch);
                } //不會(huì)一直讀,當(dāng)另一端關(guān)閉后會(huì)繼續(xù)執(zhí)行下面的代碼

                int status = 0;
                pid_t ret = waitpid(pid, &status, 0);
                if(ret == pid){
                    if(WIFEXITED(status)){ //正常退出
                        LOG(INFO, "正常退出");
                        if(WEXITSTATUS(status) == 0){ //結(jié)果正確
                            LOG(INFO, "正常退出,結(jié)果正確");
                            code = OK;
                        }
                        else{
                            LOG(INFO, "正常退出,結(jié)果不正確");
                            code = BAD_REQUEST;
                        }
                    }
                    else{
                        LOG(INFO, "異常退出");
                        code = SERVER_ERROR;
                    }
                }

                //釋放文件描述符
                close(input[0]);
                close(output[1]);
            }
            return code;
        }
        //非CGI處理
        int ProcessNonCgi()
        {
            //打開(kāi)待發(fā)送的文件
            _http_response._fd = open(_http_request._path.c_str(), O_RDONLY);
            if(_http_response._fd >= 0){ //打開(kāi)文件成功再構(gòu)建
                return OK;
            }
            return NOT_FOUND;
        }
        void BuildOkResponse()
        {
            //構(gòu)建響應(yīng)報(bào)頭
            std::string content_type = "Content-Type: ";
            content_type += SuffixToDesc(_http_response._suffix);
            content_type += LINE_END;
            _http_response._response_header.push_back(content_type);

            std::string content_length = "Content-Length: ";
            if(_http_request._cgi){ //以CGI方式請(qǐng)求
                content_length += std::to_string(_http_response._response_body.size());
            }
            else{ //以非CGI方式請(qǐng)求
                content_length += std::to_string(_http_response._size);
            }
            content_length += LINE_END;
            _http_response._response_header.push_back(content_length);
        }
        void HandlerError(std::string page)
        {
            _http_request._cgi = false; //正常的網(wǎng)頁(yè)返回,非CGI返回
            _http_response._fd = open(page.c_str(), O_RDONLY);
            std::cout<<page.c_str()<<std::endl;
            if(_http_response._fd > 0){
                std::cout<<page.c_str()<<std::endl;
                //構(gòu)建響應(yīng)報(bào)頭
                struct stat st;
                stat(page.c_str(), &st);
                std::string content_type = "Content-Type: text/html";
                content_type += LINE_END;
                _http_response._response_header.push_back(content_type);

                std::string content_length = "Content-Length: ";
                content_length += std::to_string(st.st_size);
                content_length += LINE_END;
                _http_response._response_header.push_back(content_length);

                _http_response._size = st.st_size;
            }
        }
        void BuildHttpResponseHelp()
        {
            int code = _http_response._status_code;
            //構(gòu)建狀態(tài)行
            auto& status_line = _http_response._status_line;
            status_line += HTTP_VERSION;
            status_line += " ";
            status_line += std::to_string(code);
            status_line += " ";
            status_line += CodeToDesc(code);
            status_line += LINE_END;

            //構(gòu)建響應(yīng)正文,可能包括響應(yīng)報(bào)頭
            std::string path = WEB_ROOT;
            path += "/";
            switch(code){
                case OK:
                    BuildOkResponse();
                    break;
                case NOT_FOUND:
                    path += PAGE_404;
                    HandlerError(path);
                    break;
                case BAD_REQUEST:
                    path += PAGE_400;
                    HandlerError(path);
                    break;
                case SERVER_ERROR:
                    path += PAGE_500;
                    HandlerError(path);
                    break;
                default:
                    break;
            }
        }
    public:
        EndPoint(int sock)
            :_sock(sock)
            ,_stop(false)
        {}
        bool IsStop()
        {
            return _stop;
        }
        //讀取請(qǐng)求
        void RecvHttpRequest()
        {
            if(!RecvHttpRequestLine()&&!RecvHttpRequestHeader()){ //短路求值
                ParseHttpRequestLine();
                ParseHttpRequestHeader();
                RecvHttpRequestBody();
            }
        }
        //構(gòu)建響應(yīng)
        void BuildHttpResponse()
        {
            auto& code = _http_response._status_code;
            std::string path;
            struct stat st;
            size_t pos = 0;

            if(_http_request._method != "GET"&&_http_request._method != "POST"){
                //非法請(qǐng)求
                LOG(WARNING, "method is not right");
                code = BAD_REQUEST;
                goto END;
            }
            if(_http_request._method == "GET"){
                size_t pos = _http_request._uri.find('?');
                if(pos != std::string::npos){
                    Util::CutString(_http_request._uri, _http_request._path, _http_request._query_string, "?");
                    _http_request._cgi = true; //上傳了參數(shù),需要使用CGI模式
                }
                else{
                    _http_request._path = _http_request._uri;
                }
            }
            else if(_http_request._method == "POST"){
                _http_request._path = _http_request._uri;
                _http_request._cgi = true; //上傳了參數(shù),需要使用CGI模式
            }
            else{
                //Do Nothing
            }
            path = _http_request._path;
            _http_request._path = WEB_ROOT;
            _http_request._path += path;

            if(_http_request._path[_http_request._path.size() - 1] == '/'){
                _http_request._path += HOME_PAGE;
            }
            
            std::cout<<"debug: "<<_http_request._path.c_str()<<std::endl;
            if(stat(_http_request._path.c_str(), &st) == 0){
                //資源存在
                if(S_ISDIR(st.st_mode)){ //是一個(gè)目錄,并且不會(huì)以/結(jié)尾,因?yàn)榍懊嬉呀?jīng)處理過(guò)了
                    _http_request._path += "/";
                    _http_request._path += HOME_PAGE;
                    stat(_http_request._path.c_str(), &st); //path改變,需要重新獲取屬性
                }
                else if(st.st_mode&S_IXUSR||st.st_mode&S_IXGRP||st.st_mode&S_IXOTH){ //是一個(gè)可執(zhí)行程序,需要特殊處理
                    _http_request._cgi = true; //請(qǐng)求的是一個(gè)可執(zhí)行程序,需要使用CGI模式
                }
                _http_response._size = st.st_size;
            }
            else{
                //資源不存在
                LOG(WARNING, _http_request._path + " NOT_FOUND");
                code = NOT_FOUND;
                goto END;
            }

            pos = _http_request._path.rfind('.');
            if(pos == std::string::npos){
                _http_response._suffix = ".html"; //默認(rèn)設(shè)置
            }
            else{
                _http_response._suffix = _http_request._path.substr(pos);
            }

            if(_http_request._cgi == true){
                code = ProcessCgi(); //以CGI的方式進(jìn)行處理
            }
            else{
                code = ProcessNonCgi(); //簡(jiǎn)單的網(wǎng)頁(yè)返回,返回靜態(tài)網(wǎng)頁(yè)
            }
END:
            BuildHttpResponseHelp();
        }
        //發(fā)送響應(yīng)
        void SendHttpResponse()
        {
            //發(fā)送狀態(tài)行
            send(_sock, _http_response._status_line.c_str(), _http_response._status_line.size(), 0);
            //發(fā)送響應(yīng)報(bào)頭
            for(auto& iter : _http_response._response_header){
                send(_sock, iter.c_str(), iter.size(), 0);
            }
            //發(fā)送空行
            send(_sock, _http_response._blank.c_str(), _http_response._blank.size(), 0);
            //發(fā)送響應(yīng)正文
            if(_http_request._cgi){
                auto& response_body = _http_response._response_body;
                const char* start = response_body.c_str();
                size_t size = 0;
                size_t total = 0;
                while(total < response_body.size()&&(size = send(_sock, start + total, response_body.size() - total, 0)) > 0){
                    total += size;
                }
            }
            else{
                sendfile(_sock, _http_response._fd, nullptr, _http_response._size);
                //關(guān)閉文件
                close(_http_response._fd);
            }
        }
        ~EndPoint()
        {}
};

class CallBack{
    public:
        CallBack()
        {}
        void operator()(int sock)
        {
            HandlerRequest(sock);
        }
        void HandlerRequest(int sock)
        {
            LOG(INFO, "handler request begin");
            std::cout<<"get a new link..."<<sock<<std::endl;

#ifdef DEBUG
            char buffer[4096];
            recv(sock, buffer, sizeof(buffer), 0);
            std::cout<<"------------------begin------------------"<<std::endl;
            std::cout<<buffer<<std::endl;
            std::cout<<"-------------------end-------------------"<<std::endl;
#else
            EndPoint* ep = new EndPoint(sock);
            ep->RecvHttpRequest();
            if(!ep->IsStop()){
                LOG(INFO, "Recv No Error, Begin Build And Send");
                ep->BuildHttpResponse();
                ep->SendHttpResponse();
            }
            else{
                LOG(WARNING, "Recv Error, Stop Build And Send");
            }

            close(sock);
            delete ep;
#endif
            LOG(INFO, "handler request end");
        }
        ~CallBack()
        {}
};

Makefile

bin=httpserver
cgi=test_cgi
cc=g++
LD_FLAGS=-std=c++11 -lpthread #-DDEBUG=1
curr=$(shell pwd)
src=main.cc

ALL:$(bin) $(cgi)
.PHONY:ALL

$(bin):$(src)
	$(cc) -o $@ $^ $(LD_FLAGS)

$(cgi):cgi/test_cgi.cc
	$(cc) -o $@ $^ -std=c++11

.PHONY:clean
clean:
	rm -f $(bin) $(cgi)
	rm -rf output

.PHONY:output
output:
	mkdir -p output
	cp $(bin) output
	cp -rf wwwroot output
	cp $(cgi) output/wwwroot
	cp ./cgi/shell_cgi.sh output/wwwroot
	cp ./cgi/python_cgi.py output/wwwroot
	cp ./cgi/test.html output/wwwroot

main.cc

#include <iostream>
#include <string>
#include <memory>
#include "HttpServer.hpp"

static void Usage(std::string proc)
{
    std::cout<<"Usage:\n\t"<<proc<<" port"<<std::endl;
}
int main(int argc, char* argv[])
{
    if(argc != 2){
        Usage(argv[0]);
        exit(4);
    }
    int port = atoi(argv[1]);
    std::shared_ptr<HttpServer> svr(new HttpServer(port));
    svr->InitServer();
    svr->Loop();
    return 0;
}

【基于C++HTTP 服務(wù)器的epoll 改造】,c++,http,服務(wù)器
【基于C++HTTP 服務(wù)器的epoll 改造】,c++,http,服務(wù)器
后續(xù)加上post 請(qǐng)求

原文鏈接: link文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-785692.html

到了這里,關(guān)于【基于C++HTTP 服務(wù)器的epoll 改造】的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 基于C++的簡(jiǎn)單HTTP服務(wù)器實(shí)現(xiàn)

    基于C++的簡(jiǎn)單HTTP服務(wù)器實(shí)現(xiàn)

    基于C++的簡(jiǎn)單HTTP服務(wù)器實(shí)現(xiàn) 一個(gè)Web Server就是一個(gè)服務(wù)器軟件(程序),或者是運(yùn)行這個(gè)服務(wù)器軟件的硬件(計(jì)算機(jī))。其主要功能是通過(guò)HTTP協(xié)議與客戶端(通常是瀏覽器(Browser))進(jìn)行通信,來(lái)接收,存儲(chǔ),處理來(lái)自客戶端的HTTP請(qǐng)求,并對(duì)其請(qǐng)求做出HTTP響應(yīng),返回給客戶

    2024年02月02日
    瀏覽(75)
  • 基于 Python 實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 HTTP 服務(wù)器

    基于 Python 實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 HTTP 服務(wù)器

    文章這個(gè)題目,讓我想起了大學(xué)時(shí)上《Unix 網(wǎng)絡(luò)編程》這門專業(yè)課的家庭作業(yè),題目幾乎一模一樣。 HTTP 服務(wù)器工作在服務(wù)端,主要功能包括處理來(lái)自客戶端的請(qǐng)求,管理網(wǎng)絡(luò)資源,以及生成和發(fā)送響應(yīng)給客戶端。在實(shí)際應(yīng)用中,HTTP 服務(wù)器不僅限于傳輸 HTML 文檔;它還可以傳

    2024年03月22日
    瀏覽(27)
  • 基于epoll實(shí)現(xiàn)Reactor服務(wù)器

    基于epoll實(shí)現(xiàn)Reactor服務(wù)器

    在我們調(diào)用epoll_create的時(shí)候會(huì)創(chuàng)建出epoll模型,這個(gè)模型也是利用文件描述類似文件系統(tǒng)的方式控制該結(jié)構(gòu)。 在我們調(diào)用epoll_create的時(shí)候,就會(huì)在內(nèi)核管理中創(chuàng)建一個(gè)epoll模型,并且建管理模塊地址給file結(jié)構(gòu)體,file結(jié)構(gòu)體也是連接在管理所有file結(jié)構(gòu)體的數(shù)據(jù)結(jié)構(gòu)中 所以epo

    2024年02月20日
    瀏覽(21)
  • 基于 ESP32 創(chuàng)建 HTTP Server 服務(wù)器,支持載入文件到服務(wù)器,并對(duì)載入文件進(jìn)行刪除管理

    基于 ESP32 創(chuàng)建 HTTP Server 服務(wù)器,支持載入文件到服務(wù)器,并對(duì)載入文件進(jìn)行刪除管理

    軟件編程指南參見(jiàn):HTTP 服務(wù)器 任意一款 ESP32 系列開(kāi)發(fā)板 2.4GHz 路由器熱點(diǎn) 準(zhǔn)備各種格式的文件 可基于 esp-idf/examples/protocols/http_server /file_serving 例程進(jìn)行測(cè)試 只需要設(shè)置 ESP32 連接的 2.4GHz 的 WiFi 熱點(diǎn) 即可 menuconfig — Example Connection Configuration — WiFi SSID — WiFi Password 下載固件

    2024年02月16日
    瀏覽(34)
  • Java服務(wù)器調(diào)用Python服務(wù)器進(jìn)行交互:基于Http協(xié)議的Restful風(fēng)格調(diào)用(Springboot/FastApi)

    Java服務(wù)器調(diào)用Python服務(wù)器進(jìn)行交互:基于Http協(xié)議的Restful風(fēng)格調(diào)用(Springboot/FastApi)

    實(shí)現(xiàn)Java服務(wù)器調(diào)用Python服務(wù)器進(jìn)行交互以及數(shù)據(jù)傳輸,可采用以下方法,親測(cè)有效: 基于Restful風(fēng)格進(jìn)行請(qǐng)求調(diào)用: 框架 : Java服務(wù)器采用Springboot框架進(jìn)行搭建服務(wù) python服務(wù)器采用FastApi框架進(jìn)行搭建服務(wù) 思路 :前端–Java–python–Java–前端 代碼設(shè)計(jì) :Axios-@PostMapping-請(qǐng)求

    2024年04月26日
    瀏覽(17)
  • 【Qt-4】QT基于qhttp-server搭建http服務(wù)器

    【Qt-4】QT基于qhttp-server搭建http服務(wù)器

    寫在前面 :雖然qhttp-server編譯成功,已生成dll庫(kù),但在使用過(guò)程中,仍出現(xiàn)無(wú)法打開(kāi)文件: “QtSslServer/QtSslServer”的問(wèn)題,在多次解決無(wú)果后,決定放棄qhttp-server,選擇了QWebAPP,望知道的大佬可以幫忙解答一下,感謝~~ 一、環(huán)境搭建 1、下載及解壓源文件 下載QtHttpServer源碼,

    2024年02月08日
    瀏覽(20)
  • 基于Spring Boot2.0 & HTTP/2 實(shí)現(xiàn)服務(wù)器、客戶端

    基于Spring Boot2.0 & HTTP/2 實(shí)現(xiàn)服務(wù)器、客戶端

    HTTP協(xié)議由于其無(wú)狀態(tài)的特性以及超高的普及率,是當(dāng)下大部分網(wǎng)站選擇使用的應(yīng)用層協(xié)議。然而,HTTP/1.x的底層傳輸方式的幾個(gè)特性,已經(jīng)對(duì)應(yīng)用的整體性能產(chǎn)生了負(fù)面影響。特別是,HTTP/1.0在每次的TCP連接上只允許發(fā)送一次請(qǐng)求,在HTTP/1.1中增加了請(qǐng)求管線,但是這僅僅解決

    2023年04月09日
    瀏覽(83)
  • 基于epoll的TCP服務(wù)器端(C++)

    網(wǎng)絡(luò)編程——C++實(shí)現(xiàn)socket通信(TCP)高并發(fā)之epoll模式_tcp通信c++ 多客戶端epoll_n大橘為重n的博客-CSDN博客 網(wǎng)絡(luò)編程——C++實(shí)現(xiàn)socket通信(TCP)高并發(fā)之select模式_n大橘為重n的博客-CSDN博客 server.cpp? ?client.cpp

    2024年02月12日
    瀏覽(22)
  • Android-音視頻學(xué)習(xí)系列-(八)基于-Nginx-搭建(rtmp、http)直播服務(wù)器

    Android-音視頻學(xué)習(xí)系列-(八)基于-Nginx-搭建(rtmp、http)直播服務(wù)器

    #!/bin/sh HTTP_FLV_MODULE_PATH=…/nginx-http-flv-module-1.2.7 OpenSSL_PATH=…/openssl-1.1.1d #–prefix=./bin 代表編譯完成之后輸出的路徑地址 #–add-module 將拓展模塊添加到當(dāng)前一起編譯 ./configure --prefix=./bin –add-module= H T T P F L V M O D U L E P A T H ? ? ? w i t h ? o p e n s s l = HTTP_FLV_MODULE_PATH --with

    2024年04月15日
    瀏覽(32)
  • 基于多反應(yīng)堆的高并發(fā)服務(wù)器【C/C++/Reactor】(中)HttpRequest模塊 解析http請(qǐng)求協(xié)議

    基于多反應(yīng)堆的高并發(fā)服務(wù)器【C/C++/Reactor】(中)HttpRequest模塊 解析http請(qǐng)求協(xié)議

    一、HTTP響應(yīng)報(bào)文格式 二、根據(jù)解析出的原始數(shù)據(jù),對(duì)客戶端的請(qǐng)求做出處理? processHttpRequest? 1.解碼字符串?? 解決瀏覽器無(wú)法訪問(wèn)帶特殊字符的文件得到問(wèn)題 2.判斷文件擴(kuò)展名,返回對(duì)應(yīng)的 Content-Type(Mime-Type) 3.發(fā)送文件??sendFile 4.發(fā)送目錄 三、解析http請(qǐng)求協(xié)議? parseHttpR

    2024年02月02日
    瀏覽(25)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包