NATS 訊息系統的 AC 用戶端。
請前往此處以取得線上文檔,並查看常見問題。
此 NATS 客戶端實作很大程度上是基於 NATS GO 客戶端。支援 Mac OS/X、Linux 和 Windows(儘管我們沒有特定的平台支援矩陣)。
有多個具有 NATS C 客戶端庫的套件管理器可用。如果您知道此清單中未包含的內容,請提交 PR 來添加它!
首先,下載原始碼:
git clone [email protected]:nats-io/nats.c.git .
若要建置庫,請使用 CMake。請注意,預設情況下,將建立 NATS Streaming API 並將其包含在 NATS 庫中。如果您不想建立與 Streaming 相關的 API,請參閱下文。
確保 CMake 已新增到您的路徑中。如果在 Windows 上構建,請從 Visual Studio 工具選單中開啟命令 shell,然後選擇適當的命令 shell(分別用於 64 或 32 位元建置的 x64 或 x86)。您可能還需要以管理員權限執行它。
從根源樹建立一個build
目錄(任何名稱都可以),然後cd
會進入該目錄。然後第一次發出此命令:
cmake ..
在某些體系結構中,您可能會遇到mutex.co
的編譯錯誤,因為不支援我們在旋轉嘗試取得鎖定時用於產生的彙編指令。
您可能會遇到此類建置錯誤:
/tmp/cc1Yp7sD.s: Assembler messages:
/tmp/cc1Yp7sD.s:302: Error: selected processor does not support ARM mode `yield'
src/CMakeFiles/nats_static.dir/build.make:542: recipe for target 'src/CMakeFiles/nats_static.dir/unix/mutex.c.o' failed
如果是這種情況,您可以透過啟用NATS_BUILD_NO_SPIN
標誌來解決此問題(如果不使用 CMake 進行編譯,請使用-DNATS_NO_SPIN
):
cmake .. -DNATS_BUILD_NO_SPIN=ON
如果您之前曾建置過該程式庫,則可能需要執行make clean
,或在執行 cmake 命令之前刪除並重新建立建置目錄。
要在 Windows 上構建,您需要選擇構建生成器。例如,要選擇nmake
,您可以執行:
cmake .. -G "NMake Makefiles"
運行cmake -h
將為您提供可能的選項清單和所有生成器名稱。
或者,您可以運行 GUI 版本。從同一個建置指令 shell 啟動 GUI:
c:program files (x86)CMakebincmake-gui.exe
如果您從空的建置目錄開始,則需要選擇來源和建置目錄,然後按一下Configure
。在這裡,您將能夠從下拉方塊中選擇建置生成器的名稱。完成後,按一下Generate
。然後您可以返回命令 shell 或 Visual Studio 並進行建置。
要修改某些建置選項,您需要編輯快取並重建。
make edit_cache
請注意,如果您在 Windows 上建置並選擇了“NMake Makefiles”,請將以下所有對make
引用替換為nmake
。
編輯快取可讓您選擇建置類型(調試、發布等)、體系結構(64 或 32 位元)等。
預設目標將建立所有內容,即靜態和共享 NATS 庫以及範例和測試程序。每個都位於建置目錄下各自的目錄中: src
、 examples
和test
。
make install
將複製資料夾install/lib
中的靜態函式庫和共用函式庫以及install/include
中的公共標頭。
預設情況下,該程式庫是使用 TLS 支援建構的。您可以從 cmake gui make edit_cache
停用此功能,並將NATS_BUILD_WITH_TLS
選項切換為OFF
,或直接將此選項傳遞給cmake
指令:
cmake .. -DNATS_BUILD_WITH_TLS=OFF
從2.0.0
開始,在使用 TLS/SSL 支援進行建置時,始終會驗證伺服器憑證的預期主機名稱。這表示 URL 中或透過選項natsOptions_SetExpectedHostname()
提供的主機名稱將用於檢查憑證中存在的主機名稱。在2.0.0
之前,僅當呼叫選項natsOptions_SetExpectedHostname()
時才會驗證主機名稱。
儘管我們建議保留新的預設行為,但您可以透過關閉此選項建置庫來恢復先前的行為:
cmake .. -DNATS_BUILD_TLS_FORCE_HOST_VERIFY=OFF
NATS C 用戶端是使用 OpenSSL 程式庫中的 API 建構的。預設情況下,我們使用3.0+
API。由於不再支援 OpenSSL 1.0.2
,從 NATS C Client v3.6.0
版本開始,CMake 變數NATS_BUILD_TLS_USE_OPENSSL_1_1_API
現在預設為ON
(如果您要設定新環境),並將使用1.1+
版本的 OpenSSL API / 3.0+
API。透過將此 CMake 選項設為OFF
,您仍然可以使用 OpenSSL 1.0.2
函式庫進行編譯:
cmake .. -DNATS_BUILD_TLS_USE_OPENSSL_1_1_API=OFF
變數NATS_BUILD_TLS_USE_OPENSSL_1_1_API
已棄用,這意味著將來該選項將被簡單地刪除,並且僅使用 OpenSSL 3.0+
API。庫中使用舊版 OpenSSL API 的程式碼也將被刪除。
請注意, v2.0.0
中已棄用的變數NATS_BUILD_WITH_TLS_CLIENT_METHOD
現已刪除。
由於 NATS C 用戶端動態連結到 OpenSSL 庫,因此您需要確保隨後針對 OpenSSL 1.1+/3.0+ 庫執行應用程式。
如果要連結到靜態 OpenSSL 庫,則需要刪除CMakeCache.txt
並使用附加選項重新產生它:
rm CMakeCache.txt
cmake .. -DNATS_BUILD_OPENSSL_STATIC_LIBS=ON
然後呼叫make
(或等效函數,取決於您的平台),這應該確保庫(以及範例和/或測試套件可執行檔)連結到 OpenSSL 庫(如果 CMake 找到了它)。
在建立具有串流支援的庫時,NATS 庫使用 libprotobuf-c 庫。當 cmake 第一次執行時(或刪除CMakeCache.txt
並再次呼叫cmake ..
後),它正在尋找 libprotobuf-c 函式庫。如果沒有找到,則會列印一條訊息並且建置過程失敗。 CMake 在通常找到庫的目錄中搜尋庫。但是,如果您想指定庫所在的特定目錄,則需要這樣做:
cmake .. -DNATS_PROTOBUF_DIR=
預設情況下將使用靜態庫。如果您想更改它,或者庫沒有預期的名稱,您需要執行以下操作:
# Use the library named mylibproto.so located at /my/location
cmake .. -DNATS_PROTOBUF_LIBRARY=/my/location/mylibproto.so
如果包含頭位於不同的目錄中,則可以將兩者組合起來
# Use the library named mylibproto.so located at /my/location and the directory protobuf-c/ containing protobuf-c.h located at /my/other/location
cmake .. -DNATS_PROTOBUF_LIBRARY=/my/location/mylibproto.so -DNATS_PROTOBUF_DIR=/my/other/location
如果您不想建立要包含在 NATS 庫中的 NATS Streaming API:
cmake .. -DNATS_BUILD_STREAMING=OFF
當使用新的 NATS 2.0 安全功能時,庫需要在連接或重新連接期間對伺服器發送的一些「隨機數」進行簽署。我們使用 Ed25519 公鑰簽署。該庫附帶了一些執行簽名的程式碼。在大多數情況下,這會沒問題,但如果效能是一個問題(特別是如果您打算大量使用natsConnection_Sign()
函數),您將可以選擇使用 Libsodium 庫進行建置。
請按照此處有關如何安裝 libsodium 庫的說明進行操作。
在macOS上,您可以使用brew
:
brew install libsodium
在 Linux 上,您可以使用apt-get
apt-get install libsodium-dev
安裝後,您可以透過先啟用 libsodium 函式庫來重建 NATS C 客戶端:
cmake .. -DNATS_BUILD_USE_SODIUM=ON
如果您將 libsodium 庫安裝在 CMake 無法找到的非標準位置,則可以指定此目錄的位置:
cmake .. -DNATS_BUILD_USE_SODIUM=ON -DNATS_SODIUM_DIR=/my/path/to/libsodium
在valgrind
可用的平台上,您可以透過記憶體檢查來執行測試。這是一個例子:
make test ARGS="-T memcheck"
或者,您可以直接呼叫ctest
程式:
ctest -T memcheck -V -I 1,4
上面的命令將使用valgrind
( -T memcheck
) 運行測試,並帶有詳細輸出 ( -V
),並運行從 1 到 4 的測試 ( -I 1,4
)。
如果將測試新增至test/test.c
,則需要將其新增至list_test.txt
檔案中。每個條目僅包含測試名稱,函數的名稱必須相同,並帶有test_
前綴。該列表按字母順序排列,但不一定如此,您可以在任何地方添加。
如果您要新增基準測試,則應將其新增至list_bench.txt
中。這些測試有不同的標籤( -L 'bench'
)並在 CI 上單獨執行。
您需要重新執行cmake
以使變更生效:
cmake ..
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ivan/nats.c/build
您可以使用以下環境變數來影響測試套件的行為。
當使用記憶體檢查運行時,時序會發生變化,整體效能會變慢。以下變數允許測試套件調整測試期間使用的一些值:
export NATS_TEST_VALGRIND=yes
在 Windows 上,將set
它而不是export
。
在詳細模式下執行測試時,以下環境變數可讓您從測試本身查看伺服器輸出。如果沒有此選項,伺服器輸出將被靜音:
export NATS_TEST_KEEP_SERVER_OUTPUT=yes
如果要變更預設伺服器執行檔名稱 ( nats-server.exe
) 或指定特定位置,請使用下列環境變數:
set NATS_TEST_SERVER_EXE=c:testnats-server.exe
公共 API 已使用 Doxygen 進行記錄。
若要產生文檔,請前往doc
目錄並鍵入以下命令:
doxygen DoxyFile.NATS.Client
如果您切換 Streaming API 的構建,且文件不再符合正在建置的內容,您可以透過切換NATS_UPDATE_DOC
建置標誌來更新文件並重建文件。
從建置目錄:
cmake .. -DNATS_UPDATE_DOC=ON
make
cd /doc
doxygen DoxyFile.NATS.Client
產生的文檔將位於html
目錄中。若要查看文檔,請將瀏覽器指向該目錄中的文件index.html
。
請前往此處以取得線上文件。
原始碼也有很好的文檔記錄。
本節列出了重要的更改,例如棄用通知等...
2.0.0
此版本引入了 NATS Server 2.0.0
使用的安全性概念,因此與伺服器版本保持一致。引入了新的 API,但最重要的變化是 TLS 連接的新預設行為:
建立安全連線時,現在始終驗證伺服器憑證的主機名,無論使用者是否呼叫natsOptions_SetExpectedHostname()
。例如,這可能會破壞使用 IP 連接到憑證中僅包含主機名稱的伺服器的應用程式。這可以透過更改應用程式以使用 URL 中的主機名稱或使用natsOptions_SetExpectedHostname()
來解決。如果這是不可能的,您可以透過建立禁用新行為的庫來恢復舊行為。請參閱#tls-support 以了解更多資訊。
此儲存庫用於包含適用於 macOS、Linux 和 Windows 的 libprotobuf-c 預編譯庫以及頭檔(位於/pbuf
目錄中)。我們現在已經刪除了這個目錄,並要求使用者單獨安裝 libprotobuf-c 函式庫。如果 CMake 無法直接找到庫,請參閱建置說明來指定庫位置。
1.8.0
natsConnStatus
枚舉值已新增前綴NATS_CONN_STATUS_
。如果您的應用程式未使用引用任何原始值,例如CONNECTED
或CLOSED
等,那麼您無需執行任何操作。如果您這樣做,您有兩個選擇:NATS_BUILD_NO_PREFIX_CONNSTS
。這可以透過建立目錄來完成: cmake .. -DNATS_BUILD_NO_PREFIX_CONNSTS=ON
examples/getstarted
目錄有一組簡單的範例,它們功能齊全,但非常簡單。目標是展示 API 的使用是多麼容易。
examples/
目錄中有一組更複雜的範例,也可用於對客戶端程式庫進行基準測試。
請注意,為簡單起見,此處不執行錯誤檢查。
natsConnection * nc = NULL ;
natsSubscription * sub = NULL ;
natsMsg * msg = NULL ;
// Connects to the default NATS Server running locally
natsConnection_ConnectTo ( & nc , NATS_DEFAULT_URL );
// Connects to a server with username and password
natsConnection_ConnectTo ( & nc , "nats://ivan:secret@localhost:4222" );
// Connects to a server with token authentication
natsConnection_ConnectTo ( & nc , "nats://myTopSecretAuthenticationToken@localhost:4222" );
// Simple publisher, sending the given string to subject "foo"
natsConnection_PublishString ( nc , "foo" , "hello world" );
// Publish binary data. Content is not interpreted as a string.
char data [] = { 1 , 2 , 0 , 4 , 5 };
natsConnection_Publish ( nc , "foo" , ( const void * ) data , 5 );
// Simple asynchronous subscriber on subject foo, invoking message
// handler 'onMsg' when messages are received, and not providing a closure.
natsConnection_Subscribe ( & sub , nc , "foo" , onMsg , NULL );
// Simple synchronous subscriber
natsConnection_SubscribeSync ( & sub , nc , "foo" );
// Using a synchronous subscriber, gets the first message available, waiting
// up to 1000 milliseconds (1 second)
natsSubscription_NextMsg ( & msg , sub , 1000 );
// Destroy any message received (asynchronously or synchronously) or created
// by your application. Note that if 'msg' is NULL, the call has no effect.
natsMsg_Destroy ( msg );
// Unsubscribing
natsSubscription_Unsubscribe ( sub );
// Destroying the subscription (this will release the object, which may
// result in freeing the memory). After this call, the object must no
// longer be used.
natsSubscription_Destroy ( sub );
// Publish requests to the given reply subject:
natsConnection_PublishRequestString ( nc , "foo" , "bar" , "help!" );
// Sends a request (internally creates an inbox) and Auto-Unsubscribe the
// internal subscriber, which means that the subscriber is unsubscribed
// when receiving the first response from potentially many repliers.
// This call will wait for the reply for up to 1000 milliseconds (1 second).
natsConnection_RequestString ( & reply , nc , "foo" , "help" , 1000 );
// Closing a connection (but not releasing the connection object)
natsConnection_Close ( nc );
// When done with the object, free the memory. Note that this call
// closes the connection first, in other words, you could have simply
// this call instead of natsConnection_Close() followed by the destroy
// call.
natsConnection_Destroy ( nc );
// Message handler
void
onMsg ( natsConnection * nc , natsSubscription * sub , natsMsg * msg , void * closure )
{
// Prints the message, using the message getters:
printf ( "Received msg: %s - %.*sn" ,
natsMsg_GetSubject ( msg ),
natsMsg_GetDataLength ( msg ),
natsMsg_GetData ( msg ));
// Don't forget to destroy the message!
natsMsg_Destroy ( msg );
}
對 JetStream 的支援從庫的v3.0.0
版本和 NATS Server v2.2.0+
開始,儘管取得 JetStream 特定錯誤代碼需要v2.3.0+
版本的伺服器。某些配置選項僅從v2.3.3
開始可用,因此我們建議您使用最新的 NATS Server 版本以獲得更好的體驗。
請參閱examples
目錄中名為js-xxx.c
的範例,以了解如何使用 API 的範例。新物件和 API 已完整記錄在線上文件中。
// Connect to NATS
natsConnection_Connect ( & conn , opts );
// Initialize and set some JetStream options
jsOptions jsOpts ;
jsOptions_Init ( & jsOpts );
jsOpts . PublishAsync . MaxPending = 256 ;
// Create JetStream Context
natsConnection_JetStream ( & js , conn , & jsOpts );
// Simple Stream Publisher
js_Publish ( & pa , js , "ORDERS.scratch" , ( const void * ) "hello" , 5 , NULL , & jerr );
// Simple Async Stream Publisher
for ( i = 0 ; i < 500 ; i ++ )
{
js_PublishAsync ( js , "ORDERS.scratch" , ( const void * ) "hello" , 5 , NULL );
}
// Wait for up to 5 seconds to receive all publish acknowledgments.
jsPubOptions_Init ( & jsPubOpts );
jsPubOpts . MaxWait = 5000 ;
js_PublishAsyncComplete ( js , & jsPubOpts );
// One can get the list of all pending publish async messages,
// to either resend them or simply destroy them.
natsMsgList pending ;
s = js_PublishAsyncGetPendingList ( & pending , js );
if ( s == NATS_OK )
{
int i ;
for ( i = 0 ; i < pending . Count ; i ++ )
{
// There could be a decision to resend these messages or not.
if ( your_decision_to_resend ( pending . Msgs [ i ]))
{
// If the call is successful, pending.Msgs[i] will be set
// to NULL so destroying the pending list will not destroy
// this message since the library has taken ownership back.
js_PublishMsgAsync ( js , & ( pending . Msgs [ i ]), NULL );
}
}
// Destroy the pending list object and all messages still in that list.
natsMsgList_Destroy ( & pending );
}
// To create an asynchronous ephemeral consumer
js_Subscribe ( & sub , js , "foo" , myMsgHandler , myClosure , & jsOpts , NULL , & jerr );
// Same but use a subscription option to ask the callback to not do auto-ack.
jsSubOptions so ;
jsSubOptions_Init ( & so );
so . ManualAck = true;
js_Subscribe ( & sub , js , "foo" , myMsgHandler , myClosure , & jsOpts , & so , & jerr );
// Or to bind to an existing specific stream/durable:
jsSubOptions_Init ( & so );
so . Stream = "MY_STREAM" ;
so . Consumer = "my_durable" ;
js_Subscribe ( & sub , js , "foo" , myMsgHandler , myClosure , & jsOpts , & so , & jerr );
// Synchronous subscription:
js_SubscribeSync ( & sub , js , "foo" , & jsOpts , & so , & jerr );
jsStreamConfig cfg ;
// Connect to NATS
natsConnection_Connect ( & conn , opts );
// Create JetStream Context
natsConnection_JetStream ( & js , conn , NULL );
// Initialize the configuration structure.
jsStreamConfig_Init ( & cfg );
// Provide a name
cfg . Name = "ORDERS" ;
// Array of subjects and its size
cfg . Subjects = ( const char * [ 1 ]){ "ORDERS.*" };
cfg . SubjectsLen = 1 ;
// Create a Stream. If you are not interested in the returned jsStreamInfo object,
// you can pass NULL.
js_AddStream ( NULL , js , & cfg , NULL , & jerr );
// Update a Stream
cfg . MaxBytes = 8 ;
js_UpdateStream ( NULL , js , & cfg , NULL , & jerr );
// Delete a Stream
js_DeleteStream ( js , "ORDERS" , NULL , & jerr );
實驗功能!我們保留更改 API 的權利,而不必更改函式庫的主要版本。
KeyValue 儲存體是基於 JetStream 的物化視圖。儲存桶是一個流,鍵是該流中的主題。
部分功能需要 NATS Server v2.6.2
,因此我們建議您使用最新的 NATS Server 版本以獲得更好的體驗。
新物件和 API 已完整記錄在線上文件中。
如何建立 KeyValue 儲存空間的範例:
jsCtx * js = NULL ;
kvStore * kv = NULL ;
kvConfig kvc ;
// Assume we got a JetStream context in `js`...
kvConfig_Init ( & kvc );
kvc . Bucket = "KVS" ;
kvc . History = 10 ;
s = js_CreateKeyValue ( & kv , js , & kvc );
// Do some stuff...
// This is to free the memory used by `kv` object,
// not delete the KeyValue store in the server
kvStore_Destroy ( kv );
這展示瞭如何「綁定」到現有的:
jsCtx * js = NULL ;
kvStore * kv = NULL ;
// Assume we got a JetStream context in `js`...
s = js_KeyValue ( & kv , ks , "KVS" );
// Do some stuff...
// This is to free the memory used by `kv` object,
// not delete the KeyValue store in the server
kvStore_Destroy ( kv );
這是刪除伺服器中的 KeyValue 儲存空間的方法:
jsCtx * js = NULL ;
// Assume we got a JetStream context in `js`...
s = js_DeleteKeyValue ( js , "KVS" );
這是為給定鍵賦值的方法:
kvStore * kv = NULL ;
uint64_t rev = 0 ;
// Assume we got a kvStore...
s = kvStore_PutString ( & rev , kv , "MY_KEY" , "my value" );
// If the one does not care about getting the revision, pass NULL:
s = kvStore_PutString ( NULL , kv , "MY_KEY" , "my value" );
上面為給定的鍵放置了一個值,但如果想確保僅當該鍵以前從未存在過時才為該鍵放置該值,則可以呼叫:
// Same note than before: if "rev" is not needed, pass NULL:
s = kvStore_CreateString ( & rev , kv , "MY_KEY" , "my value" );
當且僅當伺服器中的最後一個修訂版與傳遞給此 API 的修訂版相符時,才可以更新金鑰:
// This would update the key "MY_KEY" with the value "my updated value" only if the current revision (sequence number) for this key is 10.
s = kvStore_UpdateString ( & rev , kv , "MY_KEY" , "my updated value" , 10 );
這是獲取密鑰的方法:
kvStore * kv = NULL ;
kvEntry * e = NULL ;
// Assume we got a kvStore...
s = kvStore_Get ( & e , kv , "MY_KEY" );
// Then we can get some fields from the entry:
printf ( "Key value: %sn" , kvEntry_ValueString ( e ));
// Once done with the entry, we need to destroy it to release memory.
// This is NOT deleting the key from the server.
kvEntry_Destroy ( e );
這是清除密鑰的方法:
kvStore * kv = NULL ;
// Assume we got a kvStore...
s = kvStore_Purge ( kv , "MY_KEY" );
這將刪除伺服器中的密鑰:
kvStore * kv = NULL ;
// Assume we got a kvStore...
s = kvStore_Delete ( kv , "MY_KEY" );
為給定鍵創建“觀察者”:
kvWatcher * w = NULL ;
kvWatchOptions o ;
// Assume we got a kvStore...
// Say that we are not interested in getting the
// delete markers...
// Initialize a kvWatchOptions object:
kvWatchOptions_Init ( & o );
o . IgnoreDeletes = true;
// Create the watcher
s = kvStore_Watch ( & w , kv , "foo.*" , & o );
// Check for error..
// Now get updates:
while ( some_condition )
{
kvEntry * e = NULL ;
// Wait for the next update for up to 5 seconds
s = kvWatcher_Next ( & e , w , 5000 );
// Do something with the entry...
// Destroy to release memory
kvEntry_Destroy ( e );
}
// When done with the watcher, it needs to be destroyed to release memory:
kvWatcher_Destroy ( w );
若要取得密鑰的歷史記錄:
kvEntryList l ;
int i ;
// The list is defined on the stack and will be initilized/updated by this call:
s = kvStore_History ( & l , kv , "MY_KEY" , NULL );
for ( i = 0 ; i < l . Count ; i ++ )
{
kvEntry * e = l . Entries [ i ];
// Do something with the entry...
}
// When done with the list, call this to free entries and the content of the list.
kvEntryList_Destroy ( & l );
// In order to set a timeout to get the history, we need to do so through options:
kvWatchOptions o ;
kvWatchOptions_Init ( & o );
o . Timeout = 5000 ; // 5 seconds.
s = kvStore_History ( & l , kv , "MY_KEY" , & o );
這是獲取儲存桶密鑰的方式:
kvKeysList l ;
int i ;
// If no option is required, pass NULL as the last argument.
s = kvStore_Keys ( & l , kv , NULL );
// Check error..
// Go over all keys:
for ( i = 0 ; i < l . Count ; i ++ )
printf ( "Key: %sn" , l . Keys [ i ]);
// When done, list need to be destroyed.
kvKeysList_Destroy ( & l );
// If option need to be specified:
kvWatchOptions o ;
kvWatchOptions_Init ( & o );
o . Timeout = 5000 ; // 5 seconds.
s = kvStore_Keys ( & l , kv , & o );
連接到 2.2.0+ 版本的伺服器時,標頭可用。
它們與 http 標頭非常相似。它們是鍵/值對的映射,值是字串陣列。
標頭允許用戶添加有關訊息的元信息,而不會幹擾訊息負載。
請注意,如果應用程式在連接到不理解它們的伺服器時嘗試發送帶有標頭的訊息,則發布呼叫將傳回錯誤NATS_NO_SERVER_SUPPORT
。
有一個 API 可以了解目前連接的伺服器是否支援標頭:
natsStatus s = natsConnection_HasHeaderSupport ( conn );
if ( s == NATS_NO_SERVER_SUPPORT )
// deal with server not supporting this feature.
如果伺服器能夠理解標頭,但要將訊息傳遞給不理解標頭的用戶端,則標頭將被剝離,以便較舊的用戶端仍然可以接收訊息。如果應用程式依賴標頭,那麼讓所有用戶端和伺服器都使用支援標頭的版本非常重要。
有關 headers API 的更多詳細信息,請獲取示例: examples/getstarted/headers.c
。
*
通配符符合主題的任何層級的任何標記:
natsConnection_Subscribe ( & sub , nc , "foo.*.baz" , onMsg , NULL );
該訂閱者將收到發送至以下地址的訊息:
但是,它不會收到以下訊息:
>
通配符符合主題失敗的任意長度,且只能是最後一個標記。
natsConnection_Subscribe ( & sub , nc , "foo.>" , onMsg , NULL );
該訂閱者將收到發送至以下地址的任何訊息:
但是,它不會接收發送到以下位置的訊息:
發布此主題將導致上述兩個訂閱者收到訊息:
natsConnection_PublishString ( nc , "foo.bar.baz" , "got it?" );
所有具有相同隊列名稱的訂閱將形成一個隊列組。使用隊列語義,每個訊息將僅傳遞給每個隊列組的一個訂閱者。您可以根據需要擁有任意數量的佇列組。普通訂閱者將繼續按預期工作。
natsConnection_QueueSubscribe ( & sub , nc , "foo" , "job_workers" , onMsg , NULL );
(請注意,該庫需要在預設情況下使用 TLS 支援進行構建,才能使這些 API 正常工作。有關如何使用或不使用 TLS 進行構建的更多詳細信息,請參閱“構建”一章)。
SSL/TLS 連線是透過使用natsOptions
來設定的。根據您想要的安全性級別,它可以像在natsOptions_SetSecure()
呼叫中將 secure 布林值設為 true 一樣簡單。
即使具有完全的安全性(客戶端驗證伺服器證書,伺服器需要客戶端證書),設定也只涉及幾次呼叫。
// Here is the minimum to create a TLS/SSL connection:
// Create an options object.
natsOptions_Create ( & opts );
// Set the secure flag.
natsOptions_SetSecure ( opts , true);
// You may not need this, but suppose that the server certificate
// is self-signed and you would normally provide the root CA, but
// don't want to. You can disable the server certificate verification
// like this:
natsOptions_SkipServerVerification ( opts , true);
// Connect now...
natsConnection_Connect ( & nc , opts );
// That's it! On success you will have a secure connection with the server!
(...)
// This example shows what it takes to have a full SSL configuration,
// including server expected's hostname, root CA, client certificates
// and specific ciphers to use.
// Create an options object.
natsOptions_Create ( & opts );
// Set the secure flag.
natsOptions_SetSecure ( opts , true);
// For a server with a trusted chain built into the client host,
// simply designate the server name that is expected. Without this
// call, the server certificate is still verified, but not the
// hostname.
natsOptions_SetExpectedHostname ( opts , "localhost" );
// Instead, if you are using a self-signed cert and need to load in the CA.
natsOptions_LoadCATrustedCertificates ( opts , caCertFileName );
// If the server requires client certificates, provide them along with the
// private key, all in one call.
natsOptions_LoadCertificatesChain ( opts , certChainFileName , privateKeyFileName );
// You can also specify preferred ciphers if you want.
natsOptions_SetCiphers ( opts , "-ALL:HIGH" );
// Then simply pass the options object to the connect call:
natsConnection_Connect ( & nc , opts );
// That's it! On success you will have a secure connection with the server!