您是否有不需要開啟問題的問題?加入 gitter 頻道。
如果您使用uvw
並且想要表示感謝或支持該項目,請考慮成為贊助商。
你可以幫助我改變現狀。非常感謝那些支持我並且今天仍然支持我的人。
uvw
最初是一個僅包含標頭的、基於事件的、小型且易於使用的libuv
包裝器,用現代 C++ 編寫。
現在它終於可以作為可編譯的靜態函式庫使用了。
基本想法是將libuv
的C 風格介麵包裝在優雅的 C++ API 後面。
請注意, uvw
忠實於libuv
的 API,並且沒有向其介面添加任何內容。出於同樣的原因,該庫的使用者必須遵循與libuv
相同的規則。
例如,句柄應在任何其他操作之前初始化,並在不再使用時關閉。
#include <uvw.hpp>#include <記憶體>void Listen(uvw::loop &loop) { std::shared_ptr<uvw::tcp_handle> tcp = Loop.resource<uvw::tcp_handle>(); tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) { std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>(); 客戶端->on<uvw::close_event>([ptr = srv.shared_from_this()](const uvw::close_event &, uvw::tcp_handle &) { ptr->close(); }); 客戶端->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); }); srv.accept(*客戶端); 客戶端->read(); }); tcp->綁定(“127.0.0.1”, 4242); tcp->listen(); }void conn(uvw::loop &loop) {auto tcp = Loop.resource<uvw::tcp_handle>(); tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* 處理錯誤 */ }); tcp->on<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &tcp) {auto dataWrite = std::unique_ptr<char[]>(new char[2]{ 'b' , 'c' }); tcp.write(std::move(dataWrite), 2); tcp.close(); }); tcp->connect(std::string{"127.0.0.1"}, 4242); }int main() {自動迴圈 = uvw::loop::get_default();listen(*loop);conn(*loop); 循環->run(); }
編寫uvw
的主要原因是 C++ 中不存在有效的libuv
包裝器。就這樣。
為了能夠使用uvw
,使用者必須提供以下系統範圍的工具:
至少支援 C++17 的全功能編譯器。
libuv
(具體版本取決於使用的uvw
標籤)
如果您使用meson
,將為您下載 libuv
編譯測試和提取文件必須滿足以下要求:
CMake 版本 3.13 或更高版本。
Doxygen 版本 1.8 或更高版本。
請注意, libuv
是專案依賴項的一部分,在某些情況下可能會被CMake
克隆(有關更多詳細信息,請參閱下文)。
因此,用戶不必安裝它來運行測試或透過CMake
編譯uvw
庫。
您可以將uvw
與介子一起使用,只需將其添加到專案中的subprojects
目錄中即可。
若要從原始碼編譯uvw
而不將其用作子項目,請在uvw
來源目錄中執行:
$ meson setup build
如果需要靜態庫,請新增--default-library=static
$ cd build
$ meson compile
uvw
是一個雙模式庫。它可以以其僅頭檔的形式使用,也可以作為編譯的靜態函式庫使用。
以下部分描述了在這兩種情況下如何使uvw
在您自己的專案中啟動並運行。
要將uvw
用作僅包含頭檔的庫,只需包含uvw.hpp
頭檔或其他uvw/*.hpp
檔之一。
只需在文件頂部添加以下行:
#include <uvw.hpp>
然後將正確的-I
參數傳遞給編譯器以將src
目錄新增至包含路徑。
請注意,在這種情況下,使用者需要正確設定libuv
的包含目錄和庫搜尋路徑。
透過CMake
使用時,為了方便起見,會導出uvw::uvw
目標。
若要將uvw
用作編譯函式庫,請在包含項目之前在 cmake 中設定UVW_BUILD_LIBS
選項。
此選項觸發名為uvw::uvw-static
目標的產生。為了方便起見, libuv
的匹配版本也被編譯並導出為uv::uv-static
。
如果您不使用或不想使用CMake
,您仍然可以編譯所有.cpp
檔並包含所有.h
檔來完成工作。在這種情況下,使用者需要正確設定libuv
的包含目錄和庫搜尋路徑。
從libuv
的標籤v1.12.0開始, uvw
遵循語意版本控制方案。
問題是任何版本的uvw
都需要明確追蹤它所綁定的libuv
版本。
因此,後者將被附加到uvw
的版本中。舉個例子:
vU.V.W_libuv-vX.Y
特別是,以下內容適用:
UVW是uvw
的主要版本、次要版本和補丁版本。
XY是指要引用的libuv
版本(任何補丁版本都有效)。
換句話說,從現在開始,標籤將如下所示:
v1.0.0_libuv-v1.12
uvw
的分支master
將是一個正在進行中的分支,遵循libuv
的分支v1.x (至少只要它仍然是其主分支)。
該文檔基於doxygen
。建構它:
$ cd build
$ cmake ..
$ make docs
API 參考將以 HTML 格式在目錄build/docs/html
中建立。
要使用您最喜歡的瀏覽器進行導航:
$ cd build
$ your_favorite_browser docs/html/index.html
最新版本也可以在線上使用相同的版本,這是最後一個穩定的標籤。
出於顯而易見的原因,該文件主要受到官方 libuv API 文件的啟發。
要編譯和執行測試, uvw
需要libuv
和googletest
。
CMake
將在編譯其他內容之前下載並編譯這兩個函式庫。
建置測試:
$ cd build
$ cmake .. -DUVW_BUILD_TESTING=ON
$ make
$ ctest -j4 -R uvw
如果您還想測試libuv
和其他依賴項,請省略-R uvw
。
使用uvw
時只有一條規則:始終初始化資源並終止它們。
資源主要屬於兩個系列:句柄和請求。
句柄代表能夠在活動時執行某些操作的長期物件。
請求(通常)代表透過句柄或獨立執行的短期操作。
以下各節將簡要解釋初始化和終止此類資源的含義。
有關更多詳細信息,請參閱線上文件。
初始化通常在幕後執行,甚至可以忽略,只要使用loop::resource
成員函數建立句柄即可。
另一方面,句柄會保持活動狀態,直到有人明確關閉它們為止。因此,如果使用者忘記句柄,記憶體使用量將會增加。
因此規則很快就變成了永遠握緊你的手。就像呼叫它們的close
成員函數一樣簡單。
通常不需要初始化請求物件。不管怎樣,建議的建立請求的方式仍然是透過loop::resource
成員函數。
只要請求與未完成的底層活動綁定,它們就會保持活動狀態。這意味著用戶不必明確放棄請求。
因此,規則很快就變得可以隨意提出請求並忘記它。就像呼叫它們的成員函數一樣簡單。
使用uvw
要做的第一件事是創建一個循環。如果預設的就足夠了,那麼很容易這樣做:
自動循環= uvw::loop::get_default();
請注意,循環物件不需要明確關閉,即使它們提供close
成員函數以防使用者想要這樣做。
可以使用run
成員函數啟動循環。下面的兩個呼叫是等效的:
循環->run(); 循環->運行(uvw::loop::run_mode::DEFAULT);
可用模式有: DEFAULT
、 ONCE
、 NOWAIT
。請參閱libuv
的文檔以獲取更多詳細資訊。
為了建立資源並將其綁定到給定的循環,只需執行以下操作:
自動 tcp = 循環->資源<uvw::tcp_handle>();
上面的行建立並初始化一個 tcp 句柄,然後傳回指向該資源的共用指標。
使用者應該檢查指標是否已正確初始化:如果發生錯誤,則不會。
也可以建立未初始化的資源以供稍後初始化,如下所示:
自動 tcp = 循環->uninitialized_resource<uvw::tcp_handle>(); tcp->init();
所有資源也接受在任何情況下都不會被觸及的任意用戶資料。
使用者可以透過data
成員函數來設定和取得它們,如下所示:
資源->資料(std::make_shared<int>(42)); std::shared_ptr<void> 資料 = 資源->data();
資源需要std::shared_pointer<void>
並傳回它,因此歡迎任何類型的資料。
使用者在呼叫data
成員函數時可以明確指定void
以外的類型:
std::shared_ptr<int> data = resource->data<int>();
請記住,在上一節中,句柄將保持自身活動狀態,直到呼叫它的close
成員函數為止。
要了解哪些句柄仍然有效並綁定到給定循環,可以使用walk
成員函數。它傳回句柄及其類型。因此,建議使用overloaded
,以便能夠攔截所有感興趣的類型:
handle.parent().walk(uvw::重載{ [](uvw::timer_handle &h){ /* 此處定時器的應用程式碼 */ }, [](auto &&){ /* 忽略所有其他類型 */ } });
此函數也可用於完全通用的方法。例如,可以輕鬆關閉所有掛起的句柄,如下所示:
循環->步行([](auto &&h){ h.close(); });
無需跟踪它們。
uvw
提供了一種基於事件的方法,其中資源是附加偵聽器的小型事件發射器。
將偵聽器附加到資源是接收有關其操作的通知的建議方法。
偵聽器是void(event_type &, resource_type &)
類型的可呼叫對象,其中:
event_type
是它們設計的事件類型。
resource_type
是發起事件的資源的類型。
這意味著以下函數類型都是有效的:
void(event_type &, resource_type &)
void(const event_type &, resource_type &)
void(event_type &, const resource_type &)
void(const event_type &, const resource_type &)
請注意,無需保留對資源的引用,因為每當發布事件時,它們都會將自己作為參數傳遞。
on
成員函數是註冊長時間運行的偵聽器的方法:
resource.on<事件類型>(監聽器)
要了解給定類型是否存在偵聽器,該類別提供了一個has
函數模板。類似地, reset
函數範本用於重置並斷開偵聽器(如果有)。也存在reset
的非模板版本來清除整個發射器。
幾乎所有資源在出現錯誤時都會發出error_event
。
所有其他事件均特定於給定資源並記錄在 API 參考中。
下面的程式碼顯示如何使用uvw
建立一個簡單的 tcp 伺服器:
自動循環 = uvw::loop::get_default();自動 tcp = 循環->資源<uvw::tcp_handle>(); tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* 出了問題 */ }); tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) { std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>(); 客戶端->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); }); client->on<uvw::data_event>([](const uvw::data_event &, uvw::tcp_handle &) { /* 收到資料 */ }); srv.accept(*客戶端); 客戶端->read(); }); tcp->綁定(“127.0.0.1”, 4242); tcp->listen();
另請注意, uvw::tcp_handle
已經支援IPv6開箱即用。
API 參考是有關資源及其方法的更多詳細資訊的推薦文件。
如果使用者需要使用uvw
尚未封裝的功能,或者出於其他原因想要取得libuv
定義的底層資料結構,幾乎uvw
中的所有類別都可以直接存取它們。
請注意,除非使用者確切知道自己在做什麼以及有哪些風險,否則不應直接使用此功能。原始是危險的,主要是因為循環、句柄或請求的生命週期管理完全由庫控制,並且解決它可能會很快破壞事情。
話雖這麼說,原始是使用raw
成員函數的問題:
自動迴圈 = uvw::loop::get_default();自動 tcp = 迴圈->資源<uvw::tcp_handle>();uv_loop_t *raw = 迴圈->raw();uv_tcp_t *handle = tcp->raw() ;
使用原始方式需要您自擔風險,但不要指望在出現錯誤時獲得任何支援。
對基於uvw
構建的其他工具和庫感興趣?那麼您可能會發現以下內容很有用:
uvw_net
:一個包含客戶端集合(HTTP/Modbus/SunSpec)的網路庫,還包括 dns-sd/mdns 等發現實作。
如果您願意,請隨意將您的工具添加到清單中。
如果您想做出貢獻,請向分支主伺服器發送補丁作為拉取請求。
檢查貢獻者列表,了解到目前為止誰參與了。
程式碼和文件 版權所有 (c) 2016-2024 Michele Caini。
標誌版權所有 (c) 2018-2021 理查德·卡塞雷斯。
根據 MIT 許可證發布的程式碼和文件。
徽標在 CC BY-SA 4.0 下發布。
如果你想支持這個項目,可以給我一杯濃縮咖啡。
如果您發現這還不夠,請隨時以您喜歡的方式幫助我。