fcgi_responder

2025-12-07 0 415

fcgi_responder是C ++ 17库,它实现了FastCGI协议的响应者角色。它处理从Web服务器接收到的原始数据,并返回需要通过客户端代码将其发送回服务器的序列化输出。该库不处理与Web服务器的连接的实现,因此客户端可以使用他们喜欢的任何套接字编程方法。这使得fcgi_responder可移植并不受外部依赖关系。

fcgi_responder目标是成为FastCGI协议的现代且可读性的实现。与流行的FastCGI实施libfcgi相比,我们使用asio库的基准显示出100%以上的性能增长,该实现是用C编写的。

展示柜

  • 异步 – 基于fcgi_responderAsio网络框架

用法

Web服务器的处理请求

要使用fcgi_responder库,请从fcgi::Responder类中继承并实现其纯虚拟方法以提供必要的功能:

  • virtual void sendData(const std::string& data) = 0
  • virtual void processRequest(fcgi::Request&& request, fcgi::Response&& response) = 0
  • virtual void disconnect() = 0

然后,通过将传入数据传递到fcgi::Responder::receiveData方法来聆听Web服务器的连接并处理传入数据。

这是一个最小的示例,使用独立的ASIO库进行网络:

fcgi_responder/responder.h>
#include <iostream>

using unixdomain = asio::local::stream_protocol;

class Connection : public fcgi::Responder{
public:
explicit Connection(unixdomain::socket&& socket)
: socket_(std::move(socket))
{
}

void process()
{
while(isOpened_){
try {
auto receivedDataSize = socket_.read_some(asio::buffer(buffer_));
///
/// Passing read socket data with fcgi::Responder::receiveData method
///
receiveData(buffer_.data(), receivedDataSize);
}
catch(…){
isOpened_ = false;
return;
}
}
}

private:
///
/// Overriding fcgi::Responder::sendData to send response data to the web server
///
void sendData(const std::string& data) override
{
asio::write(socket_, asio::buffer(data, data.size()));
}

///
/// Overriding fcgi::Responder::disconnect to close connection with the web server
///
void disconnect() override
{
try{
socket_.shutdown(unixdomain::socket::shutdown_both);
socket_.close();
}
catch(const std::system_error& e){
std::cerr << \”socket close error:\” << e.code();
}
isOpened_ = false;
};

///
/// Overriding fcgi::Responder::processRequest to form response data
///
void processRequest(fcgi::Request&&, fcgi::Response&& response) override
{
response.setData(\”Status: 200 OK\\r\\n\”
\”Content-Type: text/html\\r\\n\”
\”\\r\\n\”
\”HELLO WORLD USING ASIO!\”);
response.send();
}

private:
unixdomain::socket socket_;
std::array<char, 65536> buffer_;
bool isOpened_ = true;
};

int main ()
{
auto socketPath = std::string{\”/tmp/fcgi.sock\”};
umask(0);
chmod(socketPath.c_str(), 0777);
unlink(socketPath.c_str());

auto io = asio::io_context{};
auto acceptor = unixdomain::acceptor{io, unixdomain::endpoint{socketPath}};

while (true) {
auto socket = acceptor.accept();
auto connection = Connection{std::move(socket)};
connection.process();
}
return 0;
}\”>

# include \" asio.hpp \"
# include < fcgi_responder /responder.h >
# include < iostream >

using unixdomain = asio::local::stream_protocol;

class Connection : public fcgi ::Responder{
public:
    explicit Connection (unixdomain::socket&& socket)
    : socket_(std::move(socket))
    {
    }

    void process ()
    {
        while (isOpened_){
            try {
                auto receivedDataSize = socket_. read_some ( asio::buffer (buffer_));
                // /
                // / Passing read socket data with fcgi::Responder::receiveData method
                // /
                receiveData (buffer_. data (), receivedDataSize);
            }
            catch (...){
                isOpened_ = false ;
                return ;
            }
        }
    }

private:
    // /
    // / Overriding fcgi::Responder::sendData to send response data to the web server
    // /
    void sendData ( const std::string& data) override
    {
        asio::write (socket_, asio::buffer (data, data. size ()));
    }

    // /
    // / Overriding fcgi::Responder::disconnect to close connection with the web server
    // /
    void disconnect () override
    {
        try {
            socket_. shutdown (unixdomain::socket::shutdown_both);
            socket_. close ();
        }
        catch ( const std::system_error& e){
            std::cerr << \" socket close error: \" << e. code ();
        }
        isOpened_ = false ;
    };

    // /
    // / Overriding fcgi::Responder::processRequest to form response data
    // /
    void processRequest (fcgi::Request&&, fcgi::Response&& response) override
    {
        response. setData ( \" Status: 200 OK \\r\\n \"
                         \" Content-Type: text/html \\r\\n \"
                         \" \\r\\n \"
                         \" HELLO WORLD USING ASIO! \" );
        response. send ();
    }

private:
    unixdomain::socket socket_;
    std::array< char , 65536 > buffer_;
    bool isOpened_ = true ;
};

int main ()
{
    auto socketPath = std::string{ \" /tmp/fcgi.sock \" };
    umask ( 0 );
    chmod (socketPath. c_str (), 0777 );
    unlink (socketPath. c_str ());

    auto io = asio::io_context{};
    auto acceptor = unixdomain::acceptor{io, unixdomain::endpoint{socketPath}};

    while ( true ) {
        auto socket = acceptor. accept ();
        auto connection = Connection{ std::move (socket)};
        connection. process ();
    }
    return 0 ;
}

检查使用QT框架的examples目录和其他示例。

向FastCGI应用程序发送请求

fcgi_responder库提供了一个可以用于将请求发送到FastCGI应用程序的fcgi::Requester类。

要使用它,从fcgi::Requester类中继承并实现其纯虚拟方法:

  • virtual void sendData(const std::string& data) = 0
  • virtual void disconnect() = 0

完成此操作后,您可以将套接字连接到侦听FastCGI应用程序,并通过调用fcgi::Requester::sendRequest方法来提出请求。请确保通过将传入数据传递到fcgi::Requester::receiveData方法来处理。

这是一个最小的示例,使用独立的ASIO库进行网络:

fcgi_responder/requester.h>
#include <iostream>

using unixdomain = asio::local::stream_protocol;

class Client : public fcgi::Requester{
public:
explicit Client(unixdomain::socket&& socket)
: socket_(std::move(socket))
{
}

void process()
{
while(isOpened_){
auto receivedDataSize = socket_.read_some(asio::buffer(buffer_));
///
/// Passing read socket data with fcgi::Requester::receiveData method
///
receiveData(buffer_.data(), receivedDataSize);
}
}

private:
///
/// Overriding fcgi::Requester::sendData to send request data to the FastCGI application
///
void sendData(const std::string& data) override
{
asio::write(socket_, asio::buffer(data, data.size()));
}

///
/// Overriding fcgi::Requester::disconnect to close connection with the FastCGI application
///
void disconnect() override
{
try{
socket_.shutdown(unixdomain::socket::shutdown_both);
socket_.close();
}
catch(const std::system_error& e){
std::cerr << \”socket close error:\” << e.code();
}
isOpened_ = false;
};

private:
unixdomain::socket socket_;
std::array<char, 65536> buffer_;
bool isOpened_ = true;
};

void onResponseReceived(const std::optional<fcgi::ResponseData>& response)
{
std::cout << \”Response:\” << std::endl;
if (response)
std::cout << response->data << std::endl;
else
std::cout << \”No response\” << std::endl;
}

int main ()
{
auto socketPath = std::string{\”/tmp/fcgi.sock\”};
auto io = asio::io_context{};
auto socket = unixdomain::socket{io};
try {
socket.connect(unixdomain::endpoint{socketPath});
}
catch(std::system_error& e){
std::cerr << \”Socket connection error:\” << e.code();
return 1;
}

auto client = Client{std::move(socket)};
client.setErrorInfoHandler([](const std::string& error){
std::cout << error << std::endl;
});
client.sendRequest({{\”REQUEST_METHOD\”,\”GET\”},
{\”REMOTE_ADDR\”,\”127.0.0.1\”},
{\”HTTP_HOST\”,\”localhost\”},
{\”REQUEST_URI\”,\”/\”}}, {}, onResponseReceived);
client.process();
return 0;
}\”>

# include \" asio.hpp \"
# include < fcgi_responder /requester.h >
# include < iostream >

using unixdomain = asio::local::stream_protocol;

class Client : public fcgi ::Requester{
public:
    explicit Client (unixdomain::socket&& socket)
    : socket_(std::move(socket))
    {
    }

    void process ()
    {
        while (isOpened_){
            auto receivedDataSize = socket_. read_some ( asio::buffer (buffer_));
            // /
            // / Passing read socket data with fcgi::Requester::receiveData method
            // /
            receiveData (buffer_. data (), receivedDataSize);
        }
    }

private:
    // /
    // / Overriding fcgi::Requester::sendData to send request data to the FastCGI application
    // /
    void sendData ( const std::string& data) override
    {
        asio::write (socket_, asio::buffer (data, data. size ()));
    }

    // /
    // / Overriding fcgi::Requester::disconnect to close connection with the FastCGI application
    // /
    void disconnect () override
    {
        try {
            socket_. shutdown (unixdomain::socket::shutdown_both);
            socket_. close ();
        }
        catch ( const std::system_error& e){
            std::cerr << \" socket close error: \" << e. code ();
        }
        isOpened_ = false ;
    };

private:
    unixdomain::socket socket_;
    std::array< char , 65536 > buffer_;
    bool isOpened_ = true ;
};

void onResponseReceived ( const std::optional<fcgi::ResponseData>& response)
{
    std::cout << \" Response: \" << std::endl;
    if (response)
        std::cout << response-> data << std::endl;
    else
        std::cout << \" No response \" << std::endl;
}

int main ()
{
    auto socketPath = std::string{ \" /tmp/fcgi.sock \" };
    auto io = asio::io_context{};
    auto socket = unixdomain::socket{io};
    try {
        socket. connect (unixdomain::endpoint{socketPath});
    }
    catch (std::system_error& e){
        std::cerr << \" Socket connection error: \" << e. code ();
        return 1 ;
    }

    auto client = Client{ std::move (socket)};
    client. setErrorInfoHandler ([]( const std::string& error){
        std::cout << error << std::endl;
    });
    client. sendRequest ({{ \" REQUEST_METHOD \" , \" GET \" },
                        { \" REMOTE_ADDR \" , \" 127.0.0.1 \" },
                        { \" HTTP_HOST \" , \" localhost \" },
                        { \" REQUEST_URI \" , \" / \" }}, {}, onResponseReceived);
    client. process ();
    return 0 ;
}

安装

从项目的cmakelists.txt下载并链接库:

fcgi_responder
GIT_REPOSITORY \”https://gith**u*b.com/kamchatka-volcano/fcgi_responder.git\”
GIT_TAG \”origin/master\”
)
#uncomment if you need to install fcgi_responder with your target
#set(INSTALL_ fcgi_responder ON)
FetchContent_MakeAvailable( fcgi_responder )

add_executable(${PROJECT_NAME})
target_link_libraries(${PROJECT_NAME} PRIVATE fcgi_responder :: fcgi_responder )\”>

 cmake_minimum_required(VERSION 3.14)

include(FetchContent)

FetchContent_Declare( fcgi_responder
    GIT_REPOSITORY \"https://gith**u*b.com/kamchatka-volcano/fcgi_responder.git\"
    GIT_TAG \"origin/master\"
)
#uncomment if you need to install fcgi_responder with your target
#set(INSTALL_ fcgi_responder ON)
FetchContent_MakeAvailable( fcgi_responder )

add_executable(${PROJECT_NAME})
target_link_libraries(${PROJECT_NAME} PRIVATE fcgi_responder :: fcgi_responder )

要安装整个系统范围的库,请使用以下命令:

fcgi_responder
cmake -S . -B build
cmake –build build
cmake –install build\”>

 git clone https://gith**u*b.com/kamchatka-volcano/fcgi_responder.git
cd fcgi_responder
cmake -S . -B build
cmake --build build
cmake --install build

安装后,您可以使用find_package()命令使您的项目内有可用的库:

fcgi_responder 1.0.0 REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE fcgi_responder :: fcgi_responder )\”>

 find_package( fcgi_responder 1.0.0 REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE fcgi_responder :: fcgi_responder )

运行测试

fcgi_responder
cmake -S . -B build -DENABLE_TESTS=ON
cmake –build build
cd build/tests && ctest\”>

 cd fcgi_responder
cmake -S . -B build -DENABLE_TESTS=ON
cmake --build build 
cd build/tests && ctest

运行模糊测试

使用AFL++模糊测试工具对fcgi_responder进行了测试。该存储库包含fuzz_test/input中的输入数据,一个模糊的线束fcgi_responder _fuzzer和FUZZing Input Data Enput Data Generator fuzz_input_generator
要构建fcgi_responder _fuzzer用于调试输入数据,请运行以下命令:

fcgi_responder
cmake -S . -B build -DENABLE_FUZZ_TESTS=ON
cmake –build build\”>

 cd fcgi_responder
cmake -S . -B build -DENABLE_FUZZ_TESTS=ON
cmake --build build

要构建fcgi_responder _fuzzer以运行使用afl-fuzz实用程序运行fuzzsing测试,请运行以下命令:

fcgi_responder
LLVM_CONFIG=\”llvm-config-11\” CXX=afl-clang-fast++ cmake -S . -B afl_build -DENABLE_FUZZ_TESTS=ON
cmake –build afl_build\”>

 cd fcgi_responder
LLVM_CONFIG=\"llvm-config-11\" CXX=afl-clang-fast++ cmake -S . -B afl_build -DENABLE_FUZZ_TESTS=ON
cmake --build afl_build

调整LLVM_CONFIG变量,以指向您要使用的LLVM的版本。

使用afl-fuzz实用程序运行以下命令:

 afl-fuzz -i ./fuzz_tests/input -o ./fuzz_tests/res  -x ./fuzz_tests/afl_dict.txt -s 111 -- ./afl_build/fuzz_tests/ fcgi_responder _fuzzer @@

模糊测试的结果可以在fuzz_tests/res目录中找到。

要了解有关模糊测试的更多信息,请查看AFL ++文档和本教程。

fuzz_input_generator实用程序生成/fuzz_tests/input内部的输入数据。这是将输入数据写入文件的单元测试的修改版本。要构建它,请使用以下命令:

fcgi_responder
cmake -S . -B build -DENABLE_FUZZ_INPUT_GENERATOR=ON
cmake –build build\”>

 cd fcgi_responder
cmake -S . -B build -DENABLE_FUZZ_INPUT_GENERATOR=ON
cmake --build build

运行示例

设置您的Web服务器以使用Unix域套接字/tmp/fcgi.sock上的FastCGI协议。使用nginx,您可以使用此配置:

 server {
	listen 8088;
	server_name localhost;
	index /~;

	location / {
		try_files $uri $uri/ @fcgi;
	}
	
	location @fcgi {
		fastcgi_pass  unix:/tmp/fcgi.sock;
		include fastcgi_params;
		fastcgi_intercept_errors on;
		fastcgi_keep_conn off;
	}
}

构建并运行ASIO示例:

fcgi_responder
cmake -S . -B build -DENABLE_ASIO_EXAMPLE=ON -DENABLE_ASIO_REQUESTER_EXAMPLE=ON
cmake –build build
./build/examples/asio_example
./build/examples/asio_requester_example\”>

 cd fcgi_responder
cmake -S . -B build -DENABLE_ASIO_EXAMPLE=ON -DENABLE_ASIO_REQUESTER_EXAMPLE=ON
cmake --build build 
./build/examples/asio_example
./build/examples/asio_requester_example

或构建并运行QT示例:

fcgi_responder
cmake -S . -B build -DENABLE_QT_EXAMPLE=ON -DENABLE_QT_REQUESTER_EXAMPLE=ON
cmake –build build
./build/examples/qt_example
./build/examples/qt_requester_example\”>

 cd fcgi_responder
cmake -S . -B build -DENABLE_QT_EXAMPLE=ON -DENABLE_QT_REQUESTER_EXAMPLE=ON
cmake --build build 
./build/examples/qt_example
./build/examples/qt_requester_example

检查它在这里工作:http:// localhost:8088

运行基准

实用程序libfcgi_benchmarkfcgi_responder _benchmark用于测量本文档中图表的性能。它们可以通过以下命令构建:

fcgi_responder
cmake -S . -B build -DENABLE_LIBFCGI_BENCHMARK=ON -DENABLE_ fcgi_responder _BENCHMARK=ON
cmake –build build
./build/utils/ fcgi_responder _benchmark/ fcgi_responder _benchmark –response-size 27
./build/utils/libfcgi_benchmark/libfcgi_benchmark –response-size 27\”>

 cd fcgi_responder
cmake -S . -B build -DENABLE_LIBFCGI_BENCHMARK=ON -DENABLE_ fcgi_responder _BENCHMARK=ON
cmake --build build
./build/utils/ fcgi_responder _benchmark/ fcgi_responder _benchmark --response-size 27
./build/utils/libfcgi_benchmark/libfcgi_benchmark --response-size 27

所需的Web服务器配置与上一节相同。

可以使用ab工具来测量这两个基准的吞吐量性能:

 ab -n 20000 -c 10 http://l*ocalh**ost:8088/

执照

fcgi_responder由MS-PL许可证获得许可

下载源码

通过命令行克隆项目:

git clone https://github.com/kamchatka-volcano/fcgi_responder.git

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 开发教程 fcgi_responder https://www.zuozi.net/31786.html

angular echarts
上一篇: angular echarts
mixedfeed
下一篇: mixedfeed
常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务