C++ хэл дээрх бичил үйлчилгээ. Уран зохиол эсвэл бодит байдал уу?

C++ хэл дээрх бичил үйлчилгээ. Уран зохиол эсвэл бодит байдал уу?

Энэ нийтлэлд би docker/docker-compose болон conan багц менежер ашиглан загвар (күүки хайгч) болон C++ хэл дээр REST API үйлчилгээг бичих орчинг хэрхэн бий болгосон тухай ярих болно.

Миний backend хөгжүүлэгчээр оролцсон дараагийн хакатоны үеэр дараагийн микро үйлчилгээг бичихэд юу ашиглах вэ гэсэн асуулт гарч ирэв. Өнөөг хүртэл бичсэн бүх зүйлийг би бид хоёр бичсэн нөхөр Python-д, миний хамтрагч энэ чиглэлээр мэргэшсэн, мэргэжлийн хувьд хөгжүүлсэн backends байсан тул би ерөнхийдөө embedded систем хөгжүүлэгч байсан бөгөөд агуу бөгөөд аймшигтай C++ хэл дээр бичдэг байсан бөгөөд би Python хэлийг их сургуульд сурсан.

Тиймээс бид өндөр ачаалалтай үйлчилгээг бичих даалгавартай тулгарсан бөгөөд гол ажил нь түүнд ирж буй өгөгдлийг урьдчилан боловсруулж, мэдээллийн санд бичих явдал байв. Дахин утааны завсарлага авсны дараа нэг найз намайг C++ хөгжүүлэгчийн хувьд энэ үйлчилгээг мэргэжлийн хүмүүсийг ашиглан бичихийг санал болгов. Энэ нь илүү хурдан, илүү бүтээмжтэй байх болно гэж маргаж байгаа бөгөөд ерөнхийдөө шүүгчид багийн нөөцийг хэрхэн удирдахыг бид хэрхэн мэдэж байгаад баяртай байх болно. Би С++ хэл дээр хэзээ ч ийм зүйл хийж байгаагүй бөгөөд үлдсэн 20 гаруй цагийг тохирох номын санг хайх, эмхэтгэх, холбоход хялбархан зориулж чадна гэж хариулсан. Энгийнээр хэлэхэд би гацсан. Үүнийг бид шийдэж, Python дээр бүх зүйлийг тайван дуусгасан.

Одоо өөрийгөө албадан тусгаарлах үеэр би C++ хэл дээр үйлчилгээг хэрхэн бичих талаар бодохоор шийдсэн. Хамгийн эхний хийх зүйл бол тохирох номын сангаа шийдэх явдал байв. Миний сонголт унав POCO, учир нь энэ нь объект хандалтат хэв маягаар бичигдсэн бөгөөд ердийн баримт бичгүүдээр сайрхдаг. Мөн угсралтын системийг сонгох тухай асуулт гарч ирэв. Энэ хүртэл би зөвхөн Visual Studio, IAR болон нүцгэн makefile-тэй ажилласан. Эдгээр системүүдийн аль нь ч надад таалагдсангүй, учир нь би бүх үйлчилгээг докерын саванд ажиллуулахаар төлөвлөж байсан. Дараа нь би cmake болон сонирхолтой багц менежер олохоор шийдсэн Конан. Энэхүү багц менежер нь танд бүх хамаарлыг нэг файлд бүртгэх боломжийг олгосон

conanfile.txt
[шаардлагатай]poco/1.9.3
libpq/11.5

[үүсгүүрүүд] cmake

мөн "conan install" гэсэн энгийн тушаалаар. шаардлагатай номын сангуудыг суулгана. Мэдээжийн хэрэг, өөрчлөлт оруулах шаардлагатай байсан

CMakeLists.txt

include(build/conanbuildinfo.cmake)
conan_basic_setup()
target_link_libraries(<target_name> ${CONAN_LIBS})

Үүний дараа би PostgreSQL-тэй ажиллахад туршлага багатай, мөн манай Python үйлчилгээнүүдтэй харилцдаг номын сан байсан тул би номын сан хайж эхэлсэн. Тэгээд чи миний юу сурсныг мэдэх үү? Энэ нь POCO-д байна! Гэхдээ Конан үүнийг POCO-д байгаа гэдгийг мэдэхгүй бөгөөд үүнийг хэрхэн бүтээхээ мэдэхгүй байна; хадгалах санд хуучирсан тохиргооны файл байгаа (би энэ алдааны талаар POCO-г бүтээгчид аль хэдийн бичсэн). Энэ нь та өөр номын сан хайх хэрэгтэй болно гэсэн үг юм.

Дараа нь миний сонголт бага алдартай номын сан дээр унасан libpg. Би үнэхээр азтай байсан, энэ нь аль хэдийн конанд байсан бөгөөд бүр угсарч, угсарч байсан.

Дараагийн алхам бол хүсэлтийг боловсруулах боломжтой үйлчилгээний загвар бичих явдал байв.
Бид Poco::Util::ServerApplication-аас TemplateServerApp ангиа өвлөн авч үндсэн аргыг хүчингүй болгох ёстой.

TemplateServerApp

#pragma once

#include <string>
#include <vector>
#include <Poco/Util/ServerApplication.h>

class TemplateServerApp : public Poco::Util::ServerApplication
{
    protected:
        int main(const std::vector<std::string> &);
};

int TemplateServerApp::main(const vector<string> &)
{
    HTTPServerParams* pParams = new HTTPServerParams;

    pParams->setMaxQueued(100);
    pParams->setMaxThreads(16);

    HTTPServer s(new TemplateRequestHandlerFactory, ServerSocket(8000), pParams);

    s.start();
    cerr << "Server started" << endl;

    waitForTerminationRequest();  // wait for CTRL-C or kill

    cerr << "Shutting down..." << endl;
    s.stop();

    return Application::EXIT_OK;
}

Үндсэн аргад бид параметрүүдийг тохируулах ёстой: порт, урсгалын тоо, дарааллын хэмжээ. Хамгийн гол нь та ирж буй хүсэлтийг хариуцагчийг зааж өгөх ёстой. Үүнийг үйлдвэр байгуулах замаар хийдэг

TemplateRequestHandlerFactory

class TemplateRequestHandlerFactory : public HTTPRequestHandlerFactory
{
public:
    virtual HTTPRequestHandler* createRequestHandler(const HTTPServerRequest & request)
    {
        return new TemplateServerAppHandler;
    }
};

Миний хувьд, тэр болгонд ижил зохицуулагчийг үүсгэдэг - TemplateServerAppHandler. Энд бид бизнесийн логикоо байрлуулж болно.

TemplateServerAppHandler

class TemplateServerAppHandler : public HTTPRequestHandler
{
public:
    void handleRequest(HTTPServerRequest &req, HTTPServerResponse &resp)
    {
        URI uri(req.getURI());
        string method = req.getMethod();

        cerr << "URI: " << uri.toString() << endl;
        cerr << "Method: " << req.getMethod() << endl;

        StringTokenizer tokenizer(uri.getPath(), "/", StringTokenizer::TOK_TRIM);
        HTMLForm form(req,req.stream());

        if(!method.compare("POST"))
        {
            cerr << "POST" << endl;
        }
        else if(!method.compare("PUT"))
        {
            cerr << "PUT" << endl;
        }
        else if(!method.compare("DELETE"))
        {
            cerr << "DELETE" << endl;
        }

        resp.setStatus(HTTPResponse::HTTP_OK);
        resp.setContentType("application/json");
        ostream& out = resp.send();

        out << "{"hello":"heh"}" << endl;
        out.flush();
    }
};

Би мөн PostgreSQL-тэй ажиллах ангийн загвар үүсгэсэн. Хүснэгт үүсгэх гэх мэт энгийн SQL-г гүйцэтгэхийн тулд арга байдаг ExecuteSQL(). Илүү төвөгтэй асуултууд эсвэл өгөгдөл хайхын тулд та дамжуулан холболт авах шаардлагатай болно GetConnection() болон libpg API ашиглах. (Магадгүй дараа нь би энэ шударга бус байдлыг засах болно).

Өгөгдлийн сан

#pragma once

#include <memory>
#include <mutex>
#include <libpq-fe.h>

class Database
{
public:
    Database();
    std::shared_ptr<PGconn> GetConnection() const;
    bool ExecuteSQL(const std::string& sql);

private:
    void establish_connection();
    void LoadEnvVariables();

    std::string m_dbhost;
    int         m_dbport;
    std::string m_dbname;
    std::string m_dbuser;
    std::string m_dbpass;

    std::shared_ptr<PGconn>  m_connection;
};

Өгөгдлийн санд холбогдох бүх параметрүүдийг орчноос авсан тул та мөн .env файл үүсгэж, тохируулах хэрэгтэй.

.env

DATABASE_NAME=template
DATABASE_USER=user
DATABASE_PASSWORD=password
DATABASE_HOST=postgres
DATABASE_PORT=5432

Та бүх кодыг эндээс харж болно github.

C++ хэл дээрх бичил үйлчилгээ. Уран зохиол эсвэл бодит байдал уу?

Одоо dockerfile болон docker-compose.yml бичих эцсийн шат ирж байна. Үнэнийг хэлэхэд, энэ нь ихэнх цагийг зарцуулсан бөгөөд зөвхөн би хүн биш, номын сангуудыг байнга сэргээн засварлах шаардлагатай байсан тул Конаны алдаанаас болж. Жишээлбэл, конан шаардлагатай хамаарлыг татаж, суулгаж, бүтээхийн тулд "conan install ." -г татаж авахад хангалтгүй, өөрөөр хэлбэл -s compiler.libcxx=libstdc++11 параметрийг дамжуулах шаардлагатай. Та програмаа холбох үе шатанд олон тооны алдаа гарах эрсдэлтэй. Би энэ алдаатай хэдэн цагийн турш гацсан бөгөөд энэ нийтлэл бусад хүмүүст энэ асуудлыг богино хугацаанд шийдвэрлэхэд тусална гэж найдаж байна.

Дараа нь docker-compose.yml бичээд найзынхаа зөвлөснөөр дэмжлэг нэмсэн жигнэмэг Одоо та консолд "cookiecutter" гэж оруулаад л C++ хэл дээр тохируулсан орчинтой, PostgreSQL суулгасан REST API үйлчилгээний бүрэн хэмжээний загварыг авах боломжтой. https://github.com/KovalevVasiliy/cpp_rest_api_template.git" Тэгээд дараа нь "докер-бүрдүүлэх — бүтээх".

Энэхүү загвар нь эхлэгчдэд REST API програмуудыг агуу бөгөөд хүчирхэг, гэхдээ C++ шиг болхи хэлээр хөгжүүлэх хэцүү замд тусална гэж найдаж байна.
Мөн эндээс уншихыг зөвлөж байна энэ нь нийтлэл. Энэ нь POCO-тэй хэрхэн ажиллах, өөрийн REST API үйлчилгээг хэрхэн бичих талаар илүү дэлгэрэнгүй тайлбарладаг.

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх