Apakah Anda memiliki pertanyaan yang tidak mengharuskan Anda membuka masalah? Bergabunglah dengan saluran gitter.
Jika Anda menggunakan uvw dan ingin mengucapkan terima kasih atau mendukung proyek ini, mohon pertimbangkan untuk menjadi sponsor .
Anda dapat membantu saya membuat perbedaan. Terima kasih banyak kepada mereka yang mendukung saya dan masih mendukung saya hingga saat ini.
uvw dimulai sebagai pembungkus khusus header, berbasis peristiwa, kecil dan mudah digunakan untuk libuv yang ditulis dalam C++ modern.
Sekarang akhirnya tersedia juga sebagai perpustakaan statis yang dapat dikompilasi.
Ide dasarnya adalah untuk membungkus antarmuka C-ish dari libuv di belakang C++ API yang anggun.
Perhatikan bahwa uvw tetap setia pada API libuv dan tidak menambahkan apa pun ke antarmukanya. Untuk alasan yang sama, pengguna perpustakaan harus mengikuti aturan yang sama yang digunakan dengan libuv .
Sebagai contoh, sebuah pegangan harus diinisialisasi sebelum operasi lainnya dan ditutup setelah tidak lagi digunakan.
#include <uvw.hpp>#include <memory>void mendengarkan(uvw::loop &loop) {
std::shared_ptr<uvw::tcp_handle> tcp = loop.resource<uvw::tcp_handle>();
tcp->aktif<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
std::shared_ptr<uvw::tcp_handle> klien = srv.parent().resource<uvw::tcp_handle>();
klien->on<uvw::close_event>([ptr = srv.shared_from_this()](const uvw::close_event &, uvw::tcp_handle &) { ptr->close(); });
klien->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
srv.accept(*klien);
klien->baca();
});
tcp->mengikat("127.0.0.1", 4242);
tcp->mendengarkan();
}void conn(uvw::loop &loop) {auto tcp = loop.resource<uvw::tcp_handle>();
tcp->aktif<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* menangani kesalahan */ });
tcp->aktif<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &tcp) {auto dataWrite = std::unique_ptr<char[]>(char baru[2]{ 'b' , 'C' });
tcp.write(std::move(dataWrite), 2);
tcp.close();
});
tcp->koneksi(std::string{"127.0.0.1"}, 4242);
}int main() {auto loop = uvw::loop::get_default();listen(*loop);sambungan(*loop);
loop->jalankan();
} Alasan utama mengapa uvw ditulis adalah kenyataan bahwa tidak ada pembungkus libuv yang valid di C++. Itu saja.
Untuk dapat menggunakan uvw , pengguna harus menyediakan alat seluruh sistem berikut:
Kompiler berfitur lengkap yang mendukung setidaknya C++17.
libuv (versi mana tergantung pada tag uvw yang digunakan)
Jika Anda menggunakan meson , libuv akan diunduh untuk Anda
Persyaratan di bawah ini wajib untuk mengkompilasi pengujian dan mengekstrak dokumentasi:
CMake versi 3.13 atau lebih baru.
Doxygen versi 1.8 atau lebih baru.
Perhatikan bahwa libuv adalah bagian dari dependensi proyek dan mungkin dikloning oleh CMake dalam beberapa kasus (lihat di bawah untuk rincian lebih lanjut).
Oleh karena itu, pengguna tidak perlu menginstalnya untuk menjalankan pengujian atau saat perpustakaan uvw dikompilasi melalui CMake .
Anda dapat menggunakan uvw dengan meson hanya dengan menambahkannya ke direktori subprojects di proyek Anda.
Untuk mengkompilasi uvw dari sumber tanpa menggunakannya sebagai subproyek, di direktori sumber uvw , jalankan:
$ meson setup build
Jika Anda menginginkan perpustakaan statis, tambahkan --default-library=static
$ cd build
$ meson compile
uvw adalah perpustakaan mode ganda. Ini dapat digunakan dalam bentuk header saja atau sebagai perpustakaan statis yang dikompilasi.
Bagian berikut menjelaskan apa yang harus dilakukan dalam kedua kasus tersebut untuk mengaktifkan dan menjalankan uvw di proyek Anda sendiri.
Untuk menggunakan uvw sebagai pustaka header saja, yang diperlukan hanyalah menyertakan header uvw.hpp atau salah satu file uvw/*.hpp lainnya.
Ini masalah menambahkan baris berikut di bagian atas file:
#termasuk <uvw.hpp>
Kemudian berikan argumen -I yang tepat ke kompiler untuk menambahkan direktori src ke jalur penyertaan.
Perhatikan bahwa pengguna diharuskan untuk mengatur dengan benar jalur pencarian direktori dan perpustakaan untuk libuv dalam kasus ini.
Saat digunakan melalui CMake , target uvw::uvw diekspor demi kenyamanan.
Untuk menggunakan uvw sebagai perpustakaan terkompilasi, atur opsi UVW_BUILD_LIBS di cmake sebelum menyertakan proyek.
Opsi ini memicu pembuatan target bernama uvw::uvw-static . Versi libuv yang cocok juga dikompilasi dan diekspor sebagai uv::uv-static untuk kenyamanan.
Jika Anda tidak menggunakan atau tidak ingin menggunakan CMake , Anda masih dapat mengkompilasi semua file .cpp dan menyertakan semua file .h untuk menyelesaikan pekerjaan. Dalam hal ini, pengguna diharuskan untuk mengatur dengan benar jalur pencarian direktori dan perpustakaan yang disertakan untuk libuv .
Dimulai dengan tag v1.12.0 dari libuv , uvw mengikuti skema pembuatan versi semantik.
Masalahnya adalah versi uvw apa pun juga perlu melacak secara eksplisit versi libuv yang terikat dengannya.
Oleh karena itu, versi terakhir akan ditambahkan ke versi uvw . Sebagai contoh:
vU.V.W_libuv-vX.Y
Secara khusus, hal berikut ini berlaku:
UVW adalah versi mayor, minor, dan patch dari uvw .
XY adalah versi libuv yang menjadi acuan (di mana versi patch apa pun valid).
Dengan kata lain, tag akan terlihat seperti ini mulai sekarang:
v1.0.0_libuv-v1.12
master cabang uvw akan menjadi cabang yang sedang dalam proses yang mengikuti cabang v1.x dari libuv (setidaknya selama cabang tersebut tetap menjadi cabang masternya ).
Dokumentasinya didasarkan pada doxygen . Untuk membangunnya:
$ cd build
$ cmake ..
$ make docs
Referensi API akan dibuat dalam format HTML di dalam direktori build/docs/html .
Untuk menavigasinya dengan browser favorit Anda:
$ cd build
$ your_favorite_browser docs/html/index.html
Versi yang sama juga tersedia online untuk rilis terbaru, yaitu tag stabil terakhir.
Dokumentasi ini sebagian besar terinspirasi oleh dokumentasi resmi libuv API karena alasan yang jelas.
Untuk mengkompilasi dan menjalankan pengujian, uvw memerlukan libuv dan googletest .
CMake akan mengunduh dan mengkompilasi kedua perpustakaan sebelum mengkompilasi yang lainnya.
Untuk membuat pengujian:
$ cd build
$ cmake .. -DUVW_BUILD_TESTING=ON
$ make
$ ctest -j4 -R uvw
Hilangkan -R uvw jika Anda juga ingin menguji libuv dan dependensi lainnya.
Hanya ada satu aturan saat menggunakan uvw : selalu inisialisasi sumber daya dan hentikan.
Sumber daya sebagian besar dimiliki oleh dua keluarga: handles dan queries .
Pegangan mewakili objek berumur panjang yang mampu melakukan operasi tertentu saat aktif.
Permintaan mewakili (biasanya) operasi berumur pendek yang dilakukan melalui pegangan atau mandiri.
Bagian berikut akan menjelaskan secara singkat apa yang dimaksud dengan menginisialisasi dan mengakhiri sumber daya semacam ini.
Untuk lebih jelasnya, silakan merujuk ke dokumentasi online.
Inisialisasi biasanya dilakukan di bawah tenda dan bahkan dapat dilewati, sejauh pegangan dibuat menggunakan fungsi anggota loop::resource .
Di sisi lain, pegangan tetap hidup sampai ada yang menutupnya secara eksplisit. Oleh karena itu, penggunaan memori akan bertambah jika pengguna melupakan sebuah pegangan.
Oleh karena itu aturannya dengan cepat menjadi selalu tutup pegangan Anda . Ini semudah memanggil fungsi anggota close pada mereka.
Biasanya menginisialisasi objek permintaan tidak diperlukan. Bagaimanapun, cara yang disarankan untuk membuat permintaan masih melalui fungsi anggota loop::resource .
Permintaan akan tetap hidup selama mereka terikat pada aktivitas mendasar yang belum selesai. Artinya pengguna tidak perlu membuang permintaan secara eksplisit .
Oleh karena itu aturannya dengan cepat menjadi merasa bebas untuk membuat permintaan dan melupakannya . Ini semudah memanggil fungsi anggota pada mereka.
Hal pertama yang harus dilakukan untuk menggunakan uvw adalah membuat loop. Jika yang default sudah cukup, caranya semudah melakukan ini:
putaran otomatis = uvw::loop::get_default();
Perhatikan bahwa objek loop tidak perlu ditutup secara eksplisit, meskipun objek tersebut menawarkan fungsi anggota close jika pengguna ingin melakukannya.
Perulangan dapat dimulai menggunakan fungsi run member. Dua panggilan di bawah ini setara:
loop->jalankan(); loop->jalankan(uvw::loop::run_mode::DEFAULT);
Mode yang tersedia adalah: DEFAULT , ONCE , NOWAIT . Silakan merujuk ke dokumentasi libuv untuk rincian lebih lanjut.
Untuk membuat sumber daya dan mengikatnya ke loop tertentu, lakukan saja hal berikut:
auto tcp = loop->sumber daya<uvw::tcp_handle>();
Baris di atas membuat dan menginisialisasi pegangan tcp, lalu penunjuk bersama ke sumber daya tersebut dikembalikan.
Pengguna harus memeriksa apakah pointer telah diinisialisasi dengan benar: jika terjadi kesalahan, hal itu tidak akan terjadi.
Dimungkinkan juga untuk membuat sumber daya yang belum diinisialisasi untuk dijalankan nanti sebagai:
auto tcp = loop->uninitialized_resource<uvw::tcp_handle>(); tcp->init();
Semua sumber daya juga menerima data pengguna sewenang-wenang yang tidak akan disentuh dalam hal apa pun.
Pengguna dapat mengatur dan mendapatkannya melalui fungsi anggota data sebagai berikut:
sumber daya->data(std::make_shared<int>(42)); std::shared_ptr<void> data = sumber daya->data();
Sumber daya mengharapkan std::shared_pointer<void> dan mengembalikannya, oleh karena itu data apa pun diperbolehkan.
Pengguna dapat secara eksplisit menentukan tipe selain void saat memanggil fungsi anggota data :
std::shared_ptr<int> data = sumber daya->data<int>();
Ingat dari bagian sebelumnya bahwa sebuah pegangan akan tetap hidup sampai seseorang memanggil fungsi anggota close di atasnya.
Untuk mengetahui pegangan apa saja yang masih hidup dan terikat pada loop tertentu, terdapat fungsi anggota walk . Ia mengembalikan pegangan dengan tipenya. Oleh karena itu, penggunaan overloaded disarankan untuk dapat mencegat semua jenis kepentingan:
handle.parent().walk(uvw::overloaded{
[](uvw::timer_handle &h){ /* kode aplikasi untuk pengatur waktu di sini */ },
[](auto &&){ /* abaikan semua tipe lainnya */ }
});Fungsi ini juga dapat digunakan untuk pendekatan yang sepenuhnya umum. Misalnya, semua pegangan yang tertunda dapat ditutup dengan mudah sebagai berikut:
loop->berjalan([](otomatis &&h){ h.close(); });Tidak perlu melacaknya.
uvw menawarkan pendekatan berbasis peristiwa di mana sumber daya adalah pemancar peristiwa kecil yang menjadi tempat melekatnya pendengar.
Melampirkan pendengar ke sumber daya adalah cara yang disarankan untuk menerima pemberitahuan tentang operasi mereka.
Pendengar adalah objek yang dapat dipanggil dengan tipe void(event_type &, resource_type &) , dengan:
event_type adalah jenis acara yang telah dirancang.
resource_type adalah tipe sumber daya yang menjadi asal mula peristiwa tersebut.
Artinya semua tipe fungsi berikut ini valid:
void(event_type &, resource_type &)
void(const event_type &, resource_type &)
void(event_type &, const resource_type &)
void(const event_type &, const resource_type &)
Harap dicatat bahwa tidak perlu menyimpan referensi ke sumber daya, karena referensi tersebut akan menjadi argumen setiap kali suatu peristiwa dipublikasikan.
Fungsi on member adalah cara untuk mendaftarkan pendengar yang sudah berjalan lama:
resource.on<event_type>(pendengar)
Untuk mengetahui apakah ada pendengar untuk tipe tertentu, kelas menawarkan templat fungsi has . Demikian pula, templat fungsi reset digunakan untuk mengatur ulang dan memutuskan sambungan pendengar, jika ada. Versi reset non-templat juga ada untuk menghapus emitor secara keseluruhan.
Hampir semua sumber daya mengeluarkan error_event jika terjadi kesalahan.
Semua peristiwa lainnya bersifat spesifik untuk sumber daya tertentu dan didokumentasikan dalam referensi API.
Kode di bawah ini menunjukkan cara membuat server tcp sederhana menggunakan uvw :
loop otomatis = uvw::loop::get_default();auto tcp = loop->sumber daya<uvw::tcp_handle>();
tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* ada yang tidak beres */ });
tcp->aktif<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
std::shared_ptr<uvw::tcp_handle> klien = srv.parent().resource<uvw::tcp_handle>();
klien->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
klien->on<uvw::data_event>([](const uvw::data_event &, uvw::tcp_handle &) { /* data diterima */ });
srv.accept(*klien);
klien->baca();
});
tcp->mengikat("127.0.0.1", 4242);
tcp->mendengarkan(); Perhatikan juga bahwa uvw::tcp_handle sudah mendukung IPv6 secara langsung.
Referensi API adalah dokumentasi yang direkomendasikan untuk rincian lebih lanjut tentang sumber daya dan metodenya.
Jika pengguna perlu menggunakan fungsionalitas yang belum disertakan oleh uvw atau jika mereka ingin mendapatkan struktur data dasar seperti yang ditentukan oleh libuv karena beberapa alasan lain, hampir semua kelas di uvw memberikan akses langsung ke fungsionalitas tersebut.
Harap diperhatikan bahwa fungsi ini tidak boleh digunakan secara langsung kecuali pengguna mengetahui secara pasti apa yang mereka lakukan dan apa risikonya. Menjadi mentah itu berbahaya, terutama karena manajemen loop, pegangan, atau permintaan seumur hidup sepenuhnya dikontrol oleh perpustakaan dan mengatasinya dapat dengan cepat merusak banyak hal.
Meskipun demikian, menjadi mentah adalah masalah menggunakan fungsi anggota raw :
loop otomatis = uvw::loop::get_default();auto tcp = loop->sumber daya<uvw::tcp_handle>();uv_loop_t *raw = loop->raw();uv_tcp_t *handle = tcp->raw() ;
Lakukan secara mentah-mentah dengan risiko Anda sendiri, tetapi jangan mengharapkan dukungan apa pun jika terjadi bug.
Tertarik dengan alat dan pustaka tambahan yang dibuat berdasarkan uvw ? Anda mungkin menemukan hal berikut berguna:
uvw_net : perpustakaan jaringan dengan kumpulan klien (HTTP/Modbus/SunSpec) yang juga mencakup implementasi penemuan seperti dns-sd/mdns.
Jangan ragu untuk menambahkan alat Anda ke daftar jika Anda mau.
Jika Anda ingin berkontribusi, silakan kirimkan patch sebagai permintaan tarik terhadap master cabang.
Periksa daftar kontributor untuk melihat siapa yang telah berpartisipasi sejauh ini.
Kode dan dokumentasi Hak Cipta (c) 2016-2024 Michele Caini.
Logo Hak Cipta (c) 2018-2021 Richard Caseres.
Kode dan dokumentasi dirilis di bawah lisensi MIT.
Logo dirilis di bawah CC BY-SA 4.0.
Jika Anda ingin mendukung proyek ini, Anda dapat menawari saya espresso.
Jika menurut Anda itu tidak cukup, silakan bantu saya sesuai keinginan Anda.