基于C++的web服务端类的实现

头文件

#pragma once

#include <iostream>
#include <sstream>
#include <vector>
#include <functional>
#include <string>
#include <cstring>
#include <winsock2.h>
#include <thread>


#pragma comment(lib, "ws2_32.lib")

class HTTPRequest {
public:
    std::string method;
    std::string path;
    std::string version;
    std::vector<std::pair<std::string, std::string>> headers;
    std::string body;
};

class HTTPResponse {
public:
    int status_code;
    std::string status_desc;
    std::vector<std::pair<std::string, std::string>> headers;
    std::string body;
};

class Route {
public:
    std::string method;
    std::string path;
    std::function<void(const HTTPRequest&, HTTPResponse&)> handler;

    Route(const std::string& method_, const std::string& path_, std::function<void(const HTTPRequest&, HTTPResponse&)> handler_)
        : method(method_), path(path_), handler(handler_) {}
};

class Router {
public:
    void add_route(const std::string& method, const std::string& path, std::function<void(const HTTPRequest&, HTTPResponse&)> handler) {
        routes.push_back(Route(method, path, handler));
    }

    void handle_request(const HTTPRequest& req, HTTPResponse& resp) {
        for (const auto& route : routes) {
            if (route.method == req.method && route.path == req.path) {
                route.handler(req, resp);
                return;
            }
        }
        resp.status_code = 404;
        resp.status_desc = "Not Found";
        resp.body = "404 Not Found";
    }

private:
    std::vector<Route> routes;
};

class Server {
public:
    Server(int port_) : port(port_), router() {}

    void run() {
        WSADATA wsaData;
        int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if (result != 0) {
            std::cerr << "WSAStartup failed: " << result << std::endl;
            return;
        }

        SOCKET listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (listen_socket == INVALID_SOCKET) {
            std::cerr << "socket failed: " << WSAGetLastError() << std::endl;
            WSACleanup();
            return;
        }

        sockaddr_in service;
        service.sin_family = AF_INET;
        service.sin_addr.s_addr = INADDR_ANY;
        service.sin_port = htons(port);

        result = bind(listen_socket, reinterpret_cast<SOCKADDR*>(&service), sizeof(service));
        if (result == SOCKET_ERROR) {
            std::cerr << "bind failed: " << WSAGetLastError() << std::endl;
            closesocket(listen_socket);
            WSACleanup();
            return;
        }

        result = listen(listen_socket, SOMAXCONN);
        if (result == SOCKET_ERROR) {
            std::cerr << "listen failed: " << WSAGetLastError() << std::endl;
            closesocket(listen_socket);
            WSACleanup();
            return;
        }

        std::cout << "Listening on port " << port << std::endl;

        while (true) {
            SOCKET client_socket = accept(listen_socket, nullptr, nullptr);
            if (client_socket == INVALID_SOCKET) {
                std::cerr << "accept failed: " << WSAGetLastError() << std::endl;
                closesocket(listen_socket);
                WSACleanup();
                return;
            }

            std::thread t([this, client_socket]() {

                char recvbuf[9600];
                int recvbuflen = 9600;
                int result = recv(client_socket, recvbuf, recvbuflen, 0);
                if (result == SOCKET_ERROR) {
                    std::cerr << "recv failed: " << WSAGetLastError() << std::endl;
                    closesocket(client_socket);
                    return;
                }

                if (result < 9600)
                {
                    recvbuf[result] = '\0';
                }

                HTTPRequest req;
                parse_request(recvbuf, req);

                HTTPResponse resp;
                router.handle_request(req, resp);

                std::stringstream response_stream;
                response_stream << "HTTP/1.1 " << resp.status_code << " " << resp.status_desc << "\r\n";
                for (const auto& header : resp.headers) {
                    response_stream << header.first << ": " << header.second << "\r\n";
                }
                response_stream << "\r\n";
                response_stream << resp.body;

                std::string response_str = response_stream.str();
                result = send(client_socket, response_str.c_str(), response_str.length(), 0);
                if (result == SOCKET_ERROR) {
                    std::cerr << "send failed: " << WSAGetLastError() << std::endl;
                    closesocket(client_socket);
                    return;
                }

                std::cout << req.method << " " << req.path << " - " << resp.status_code << std::endl;

                closesocket(client_socket);
                });
            t.detach();
        }

        closesocket(listen_socket);
        WSACleanup();
    }
    void add_route(const std::string& method, const std::string& path, std::function<void(const HTTPRequest&, HTTPResponse&)> handler) {
        router.add_route(method, path, handler);
    }
private:
    int port;
    Router router;
    void parse_request(const char* request_str, HTTPRequest& req) {
        std::stringstream request_stream(request_str);

        request_stream >> req.method >> req.path >> req.version;
        request_stream.ignore(2, '\n');

        std::string line;
        while (std::getline(request_stream, line) && !line.empty() && line.back() == '\r') {
            if (line == "\r")
                break;
            line.pop_back();
            std::size_t colon_pos = line.find(':');
            if (colon_pos != std::string::npos) {
                std::string header_name = line.substr(0, colon_pos);
                std::string header_value = line.substr(colon_pos + 2); // 除去冒号和空格
                req.headers.push_back(std::make_pair(header_name, header_value));
            }
        }

        std::string body;
        char c;
        while (request_stream.get(c)) {
            if (c == '\r' && request_stream.peek() == '\n' && request_stream.ignore() &&
                request_stream.peek() == '\r' && request_stream.ignore()) {
                std::getline(request_stream, req.body);
                break;
            }
            else {
                body += c;
            }
        }
        req.body = std::move(body);
    }

#if 0
    void parse_request(const char* request_str, HTTPRequest& req) {
        std::stringstream request_stream(request_str);

        request_stream >> req.method >> req.path >> req.version;
        request_stream.ignore(2, '\n');

        std::string line;
        while (std::getline(request_stream, line) && !line.empty() && line.back() == '\r') {
            line.pop_back();
            std::size_t colon_pos = line.find(':');
            if (colon_pos != std::string::npos) {
                std::string header_name = line.substr(0, colon_pos);
                std::string header_value = line.substr(colon_pos + 2); 
                req.headers.push_back(std::make_pair(header_name, header_value));
            }
        }

        if (request_stream.peek() != EOF) {
            std::getline(request_stream, req.body);
        }

      
    }
#endif
};

用例

#include "ksam_cgin_nethttp.h"
#include <locale.h>

void handle_get_request(const HTTPRequest& req, HTTPResponse& resp) {
    std::cout << "T1-Body:" << req.body << std::endl;
    resp.body= req.body;
    resp.headers.push_back(std::make_pair("Content-Type","application/json"));
}

int main() {
    setlocale(LC_ALL, "");

    Server server(8111);


    server.add_route("GET", "/", [](const HTTPRequest&, HTTPResponse& resp) {
        resp.body = "test";
        });

    server.add_route("GET", "/t1", handle_get_request);

    server.add_route("GET", "/about", [](const HTTPRequest&, HTTPResponse& resp) {
        resp.body = "This is a C++ web service.";
        });

    server.add_route("POST", "/echo", [](const HTTPRequest& req, HTTPResponse& resp) {
        resp.headers.push_back(std::make_pair("Content-Type", "text/plain"));
    resp.body = req.body;
        });

    server.run();

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值