Dalam artikel ini, saya akan mengandalkan penggunaan libevent dalam debian + gcc + cmake , tetapi pada sistem operasi mirip unix lainnya, seharusnya tidak ada kesulitan (untuk windows, Anda perlu membangun dari sumber dan memodifikasi FindLibEvent.cmake mengajukan)
Kata pengantar
Saya telah mengembangkan layanan mikro selama sekitar 3 tahun, tetapi saya tidak memiliki pemahaman awal tentang tumpukan teknologi yang sesuai. Mencoba banyak pendekatan berbeda (beberapa di antaranya adalah OpenDDS dan apache- thrift ) tetapi akhirnya memilih RestApi .
RestApi berkomunikasi melalui permintaan HTTP, yang pada gilirannya mewakili struktur data header dan badan permintaan yang dikirimkan melalui soket. Hal pertama yang saya perhatikan adalah boost / asio, yang menyediakan soket tcp, tetapi ada kesulitan dengan jumlah pengembangan:
Anda perlu menulis penerimaan data yang benar melalui soket
Penguraian header yang ditulis sendiri
Penguraian parameter GET yang ditulis sendiri
Perutean jalur
Baris kedua adalah POCO (POcket COmponents), yang memiliki server HTTP level lebih tinggi, tetapi masih memiliki masalah dengan banyak fungsi yang ditulis sendiri. Selain itu, alat ini sedikit lebih berat dan menyediakan fungsionalitas yang mungkin tidak diperlukan (ini sedikit membebani layanan mikro kami). POCO diarahkan untuk tugas lain selain layanan mikro.
Oleh karena itu, selanjutnya mari kita bicara tentang libevent yang saya hentikan.
Mengapa libevent?
Ringan
Cepat
Stabil
Lintas platform
Telah diinstal sebelumnya pada sebagian besar OS yang mirip unix di luar kotak
Digunakan oleh banyak pengembang (lebih mudah menemukan karyawan yang akrab dengan teknologi ini)
Ada built-in router (router)
libevent . - . "" , C++ - ( ).
, ( Valgrind).
libevent libevent-dev unix- .
, dpkg -l | grep event .
, FindLibEvent.cmake ( _/cmake_modules)
# ${LIBEVENT_INCLUDE_DIR}
find_path(LIBEVENT_INCLUDE_DIR event.h
PATHS
/usr/local
/opt
PATH_SUFFIXES
include
)
# ${LIBEVENT_LIB}
find_library(LIBEVENT_LIB
NAMES
event
PATHS
/usr/local
/opt
PATH_SUFFIXES
lib
lib64
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
LIBEVENT_LIB
LIBEVENT_INCLUDE_DIR
)
( _/imported/libevent.cmake)
find_package(LibEvent REQUIRED) # FindLibEvent.cmake
add_library(libevent STATIC IMPORTED GLOBAL) # target
# target- FindLibEvent.cmake
set_target_properties(libevent PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${LIBEVENT_INCLUDE_DIR})
# target- FindLibEvent.cmake
set_target_properties(libevent PROPERTIES IMPORTED_LOCATION ${LIBEVENT_LIB})
libevent cmake- .
, 1
target_link_libraries(${PROJECT_NAME}
PUBLIC
libevent
)
, FindLibEvent.cmake
find_package(LibEvent REQUIRED)
target_link_libraries(${PROJECT_NAME}
PUBLIC
${LIBEVENT_LIB}
)
target_include_directories(${PROJECT_NAME}
PUBLIC
${LIBEVENT_INCLUDE_DIR}
)
HTTP ,
// , :
// *
// *
// * HTTP(, .)
#include <evhttp.h>
//
auto listener = std::make_shared<event_base, decltype(&event_base_free)>(event_base_new(), &event_base_free);
// HTTP
auto server = std::make_shared<evhttp, decltype(&evhttp_free)> (evhttp_new(listener.get()), &evhttp_free);
//
//
evhttp_set_gencb(server.get(), [](evhttp_request*, void*) {}, nullptr);
//
evhttp_set_cb (server.get(), "/my_path", [](evhttp_request*, void*) {}, nullptr);
//
return event_base_dispatch(listener.get());
Sekarang server kami dapat menerima permintaan, tetapi server mana pun harus merespons aplikasi klien. Untuk ini, kami menghasilkan tanggapan di penangan.
//
auto buffer = std::make_shared<evbuffer, decltype(&evbuffer_free)>(evbuffer_new(), &evbuffer_free);
evbuffer_add(buffer, msg.c_str(), msg.length()); //
evhttp_send_reply(request, HTTP_OK, "", buffer); //
Kami telah menyelesaikan komunikasi lengkap di server kami, sekarang mari kita bicara tentang mendapatkan informasi yang berguna dari permintaan klien.
Langkah pertama adalah mengurai parameter GET. Ini adalah parameter yang diteruskan dalam URI permintaan (misalnya http://www.hostname.ru ? Key = value )
struct evkeyvalq params;
evhttp_parse_query(request->uri, ¶ms); // GET
// GET-
std::string value = evhttp_find_header(¶ms, "key");
// GET-
for (auto it = params.tqh_first; it != nullptr; it = it->next.tqe_next)
std::cout << it->key << ":" << it->value << std::endl;
//
evhttp_clear_headers(¶ms);
Selanjutnya, Anda perlu mendapatkan isi permintaan
auto input = request->input_buffer; //
// ,
auto length = evbuffer_get_length(input);
char* data = new char[length];
evbuffer_copyout(input, data, length); //
std::string body(data, length); //
delete[] data; //
return body;
Fungsi Attention Callback tidak mendukung interupsi (menangkap nilai dengan fungsi lambda), oleh karena itu, hanya anggota dan metode statis yang dapat digunakan di dalam callback!