日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Zookeeper C API 指南

發(fā)布時間:2025/3/21 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Zookeeper C API 指南 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

以前自己的博客中轉載、翻譯或寫過(不過自己才疏學淺,寫的不好)一些 Zookeeper 方面的文章,但是都沒有涉及到 Zookeeper C API 的內容,今天的這篇博客是我農(nóng)歷新年的第一篇技術博客,我想詳細講講 Zookeeper C API 的使用規(guī)則和示例,算是把以前的舊帳還上吧 :-)

Zookeeper 官方頁面上提供了一些編程指南和 API 文檔,不過大部分都是 Java 示例,涉及 C API 的部分很少,只有在 ZooKeeper Programmer's Guide 中 ACL Permissions 一節(jié)講了 Zookeeper C API 中設置 ACL 應該注意的事項,正是由于缺少Zookeeper C API 相關的資料,大部分 Zookeeper C/C++ 開發(fā)者只能通過閱讀 Zookeeper C API 的源碼來了解 C API 的使用方法,本文希望在此方面給大家提供一些便利,減少 Zookeeper 新手使用 C API 的困難和恐懼,當然我自己也是一枚新手啦 :-)。

廢話不多說了,先從最基本的開始吧!

Zookeeper 偽分布式安裝

首先是 Zookeeper 的安裝,如果你沒有足夠的機器,建議在單機上通過偽分布式安裝方法來模擬 Zookeeper 集群,我在這里提供給大家一個簡單的安裝包來降低偽分布式 Zookeeper 的安裝難度,該安裝包可以模擬一個 5 Zookeeper 實例的集群。下載zookeeper-3.4.0-pseudoclusters.tar.bz2,解壓至 /tmp/ 目錄(注意,安裝包里面 dataDir 和 dataLogDir 配置已經(jīng)預設為 /tmp/ 目錄,如果你只是自己在 Zookeeper 上做一些小實驗,建議不要更改該配置,這樣在你做完了實驗以后刪除 /tmp/zookeeper/ 目錄即可),操作方法如下:

forhappy@haiping-ict:/tmp$ pwd /tmp forhappy@haiping-ict:/tmp$ tar xvf zookeeper-3.4.0-pseudoclusters.tar.bz2 forhappy@haiping-ict:/tmp$ cd zookeeper/ forhappy@haiping-ict:/tmp/zookeeper$ ls server001 server003 server005 stopZKCluster.sh server002 server004 startZKCluster.sh

然后在 /tmp/zookeeper 目錄下執(zhí)行 startZKCluster.sh 啟動 Zookeeper 服務,或者執(zhí)行 stopZKCluster.sh 停掉 Zookeeper 服務。

啟動 Zookeeper 服務:

forhappy@haiping-ict:/tmp/zookeeper$ ./startZKCluster.sh . starting zookeeper instance server001... JMX enabled by default Using config: /tmp/zookeeper/server001/zookeeper-3.4.0/bin/../conf/zoo.cfg Starting zookeeper ... STARTED starting zookeeper instance server002... JMX enabled by default Using config: /tmp/zookeeper/server002/zookeeper-3.4.0/bin/../conf/zoo.cfg Starting zookeeper ... STARTED starting zookeeper instance server003... JMX enabled by default Using config: /tmp/zookeeper/server003/zookeeper-3.4.0/bin/../conf/zoo.cfg Starting zookeeper ... STARTED starting zookeeper instance server004... JMX enabled by default Using config: /tmp/zookeeper/server004/zookeeper-3.4.0/bin/../conf/zoo.cfg Starting zookeeper ... STARTED starting zookeeper instance server005... JMX enabled by default Using config: /tmp/zookeeper/server005/zookeeper-3.4.0/bin/../conf/zoo.cfg Starting zookeeper ... STARTED

停掉 Zookeeper 服務:

forhappy@haiping-ict:/tmp/zookeeper$ ./stopZKCluster.sh . stopping zookeeper instance server001... JMX enabled by default Using config: /tmp/zookeeper/server001/zookeeper-3.4.0/bin/../conf/zoo.cfg Stopping zookeeper ... STOPPED stopping zookeeper instance server002... JMX enabled by default Using config: /tmp/zookeeper/server002/zookeeper-3.4.0/bin/../conf/zoo.cfg Stopping zookeeper ... STOPPED stopping zookeeper instance server003... JMX enabled by default Using config: /tmp/zookeeper/server003/zookeeper-3.4.0/bin/../conf/zoo.cfg Stopping zookeeper ... STOPPED stopping zookeeper instance server004... JMX enabled by default Using config: /tmp/zookeeper/server004/zookeeper-3.4.0/bin/../conf/zoo.cfg Stopping zookeeper ... STOPPED stopping zookeeper instance server005... JMX enabled by default Using config: /tmp/zookeeper/server005/zookeeper-3.4.0/bin/../conf/zoo.cfg Stopping zookeeper ... STOPPED

Zookeeper C API 安裝

Zookeeper C client 的實現(xiàn)在 src/c 目錄下,進入到該目錄安裝 Zookeeper C client,步驟如下:

$ ./configure $ make $ sudo make install

至此,基本的準備工作已經(jīng)完成,你可以通過 Zookeeper 本身提供的 Shell 來操作 Zookeeper,操作方法如下,進入 /tmp/zookeeper/server001/zookeeper-3.4.0 目錄,執(zhí)行bin/zkCli.sh -server 127.0.0.1:2181 進入 Zookeeper shell:

forhappy@haiping-ict:/tmp/zookeeper/server001/zookeeper-3.4.0$ bin/zkCli.sh -server 127.0.0.1:2181 [zk: 127.0.0.1:2181(CONNECTED) 2] help ZooKeeper -server host:port cmd argsconnect host:portget path [watch]ls path [watch]set path data [version]rmr pathdelquota [-n|-b] pathquit printwatches on|offcreate [-s] [-e] path data aclstat path [watch]close ls2 path [watch]history listquota pathsetAcl path aclgetAcl pathsync pathredo cmdnoaddauth scheme authdelete path [version]setquota -n|-b val path

在 shell 中你可以完成基本的操作,如創(chuàng)建、獲取、刪除、設置某一節(jié)點,設置節(jié)點 ACL等,可以 zookeeper shell 中通過 help 獲取相關命令的用法。

如果你按照上面的步驟完成了 Zookeeper 偽分布式的安裝,并且想繼續(xù)了解 Zookeeper C API 的使用方法,請繼續(xù)閱讀《Zookeeper C API 指南二(監(jiān)視(Wathes), 基本常量和結構體介紹)》


接上一篇《Zookeeper C API 指南一(準備工作)》,本問將重點介紹 Zookeeper 監(jiān)視(Watches),以及 Zookeeper C API 中基本的常量與結構體。

Zookeeper 監(jiān)視(Watches) 簡介

Zookeeper C API 的聲明和描述在 include/zookeeper.h 中可以找到,另外大部分的 Zookeeper C API 常量、結構體聲明也在 zookeeper.h 中,如果如果你在使用 C API 是遇到不明白的地方,最好看看 zookeeper.h,或者自己使用 doxygen 生成 Zookeeper C API 的幫助文檔。

Zookeeper 中最有特色且最不容易理解的是監(jiān)視(Watches)。Zookeeper 所有的讀操作——getData(),getChildren(), 和 exists() 都 可以設置監(jiān)視(watch),監(jiān)視事件可以理解為一次性的觸發(fā)器, 官方定義如下: a watch event is one-time trigger, sent to the client that set the watch, which occurs when the data for which the watch was set changes。對此需要作出如下理解:

  • (一次性觸發(fā))One-time trigger

    當設置監(jiān)視的數(shù)據(jù)發(fā)生改變時,該監(jiān)視事件會被發(fā)送到客戶端,例如,如果客戶端調用了 getData("/znode1", true) 并且稍后 /znode1 節(jié)點上的數(shù)據(jù)發(fā)生了改變或者被刪除了,客戶端將會獲取到 /znode1 發(fā)生變化的監(jiān)視事件,而如果 /znode1 再一次發(fā)生了變化,除非客戶端再次對 /znode1 設置監(jiān)視,否則客戶端不會收到事件通知。

  • (發(fā)送至客戶端)Sent to the client

    Zookeeper 客戶端和服務端是通過 socket 進行通信的,由于網(wǎng)絡存在故障,所以監(jiān)視事件很有可能不會成功地到達客戶端,監(jiān)視事件是異步發(fā)送至監(jiān)視者的,Zookeeper 本身提供了保序性(ordering guarantee):即客戶端只有首先看到了監(jiān)視事件后,才會感知到它所設置監(jiān)視的 znode 發(fā)生了變化(a client will never see a change for which it has set a watch until it first sees the watch event). 網(wǎng)絡延遲或者其他因素可能導致不同的客戶端在不同的時刻感知某一監(jiān)視事件,但是不同的客戶端所看到的一切具有一致的順序。

  • (被設置 watch 的數(shù)據(jù))The data for which the watch was set

    這意味著 znode 節(jié)點本身具有不同的改變方式。你也可以想象 Zookeeper 維護了兩條監(jiān)視鏈表:數(shù)據(jù)監(jiān)視和子節(jié)點監(jiān)視(data watches and child watches) getData() and exists() 設置數(shù)據(jù)監(jiān)視,getChildren() 設置子節(jié)點監(jiān)視。 或者,你也可以想象 Zookeeper 設置的不同監(jiān)視返回不同的數(shù)據(jù),getData() 和 exists() 返回 znode 節(jié)點的相關信息,而 getChildren() 返回子節(jié)點列表。因此, setData() 會觸發(fā)設置在某一節(jié)點上所設置的數(shù)據(jù)監(jiān)視(假定數(shù)據(jù)設置成功),而一次成功的 create() 操作則會出發(fā)當前節(jié)點上所設置的數(shù)據(jù)監(jiān)視以及父節(jié)點的子節(jié)點監(jiān)視。一次成功的 delete() 操作將會觸發(fā)當前節(jié)點的數(shù)據(jù)監(jiān)視和子節(jié)點監(jiān)視事件,同時也會觸發(fā)該節(jié)點父節(jié)點的child watch。

Zookeeper 中的監(jiān)視是輕量級的,因此容易設置、維護和分發(fā)。當客戶端與 Zookeeper 服務器端失去聯(lián)系時,客戶端并不會收到監(jiān)視事件的通知,只有當客戶端重新連接后,若在必要的情況下,以前注冊的監(jiān)視會重新被注冊并觸發(fā),對于開發(fā)人員來說 這通常是透明的。只有一種情況會導致監(jiān)視事件的丟失,即:通過 exists() 設置了某個 znode 節(jié)點的監(jiān)視,但是如果某個客戶端在此 znode 節(jié)點被創(chuàng)建和刪除的時間間隔內與 zookeeper 服務器失去了聯(lián)系,該客戶端即使稍后重新連接 zookeeper服務器后也得不到事件通知。

Zookeeper C API 常量與部分結構(struct)介紹

與 ACL 相關的結構與常量:

struct Id 結構為:

struct Id {char * scheme;char * id; };

struct ACL 結構為:

struct ACL {int32_t perms;struct Id id; };

struct ACL_vector 結構為:

struct ACL_vector {int32_t count;struct ACL *data;};

與 znode 訪問權限有關的常量

  • const int ZOO_PERM_READ; //允許客戶端讀取 znode 節(jié)點的值以及子節(jié)點列表。

  • const int ZOO_PERM_WRITE;// 允許客戶端設置 znode 節(jié)點的值。

  • const int ZOO_PERM_CREATE; //允許客戶端在該 znode 節(jié)點下創(chuàng)建子節(jié)點。

  • const int ZOO_PERM_DELETE;//允許客戶端刪除子節(jié)點。

  • const int ZOO_PERM_ADMIN; //允許客戶端執(zhí)行 set_acl()。

  • const int ZOO_PERM_ALL;//允許客戶端執(zhí)行所有操作,等價與上述所有標志的或(OR) 。

與 ACL IDs 相關的常量

  • struct Id ZOO_ANYONE_ID_UNSAFE; //(‘world’,’anyone’)

  • struct Id ZOO_AUTH_IDS;// (‘a(chǎn)uth’,’’)

三種標準的 ACL

  • struct ACL_vector ZOO_OPEN_ACL_UNSAFE; //(ZOO_PERM_ALL,ZOO_ANYONE_ID_UNSAFE)

  • struct ACL_vector ZOO_READ_ACL_UNSAFE;// (ZOO_PERM_READ, ZOO_ANYONE_ID_UNSAFE)

  • struct ACL_vector ZOO_CREATOR_ALL_ACL; //(ZOO_PERM_ALL,ZOO_AUTH_IDS)

與 Interest 相關的常量:ZOOKEEPER_WRITE, ZOOKEEPER_READ

這 兩個常量用于標識感興趣的事件并通知 zookeeper 發(fā)生了哪些事件。Interest 常量可以進行組合或(OR)來標識多種興趣(multiple interests: write, read),這兩個常量一般用于 zookeeper_interest() 和 zookeeper_process()兩個函數(shù)中。

與節(jié)點創(chuàng)建相關的常量:ZOO_EPHEMERAL,?ZOO_SEQUENCE

zoo_create 函數(shù)標志,ZOO_EPHEMERAL 用來標識創(chuàng)建臨時節(jié)點,ZOO_SEQUENCE 用來標識節(jié)點命名具有遞增的后綴序號(一般是節(jié)點名稱后填充 10 位字符的序號,如 /xyz0000000000, /xyz0000000001, /xyz0000000002, ...),同樣地,ZOO_EPHEMERAL,?ZOO_SEQUENCE可以組合。

與連接狀態(tài) Stat 相關的常量

以下常量均與 Zookeeper 連接狀態(tài)有關,他們通常用作監(jiān)視器回調函數(shù)的參數(shù)。

ZOOAPI const int?ZOO_EXPIRED_SESSION_STATE
ZOOAPI const int?ZOO_AUTH_FAILED_STATE
ZOOAPI const int?ZOO_CONNECTING_STATE
ZOOAPI const int?ZOO_ASSOCIATING_STATE
ZOOAPI const int?ZOO_CONNECTED_STATE

與監(jiān)視類型(Watch Types)相關的常量

以下常量標識監(jiān)視事件的類型,他們通常用作監(jiān)視器回調函數(shù)的第一個參數(shù)。

  • ZOO_CREATED_EVENT; // 節(jié)點被創(chuàng)建(此前該節(jié)點不存在),通過 zoo_exists() 設置監(jiān)視。
  • ZOO_DELETED_EVENT; // 節(jié)點被刪除,通過 zoo_exists() 和 zoo_get() 設置監(jiān)視。
  • ZOO_CHANGED_EVENT; // 節(jié)點發(fā)生變化,通過 zoo_exists() 和 zoo_get() 設置監(jiān)視。
  • ZOO_CHILD_EVENT; // 子節(jié)點事件,通過zoo_get_children() 和 zoo_get_children2()設置監(jiān)視。
  • ZOO_SESSION_EVENT; // 會話丟失
  • ZOO_NOTWATCHING_EVENT; // 監(jiān)視被移除。

Zookeeper C API 錯誤碼介紹 ZOO_ERRORS

ZOK?

正常返回

ZSYSTEMERROR?

系統(tǒng)或服務器端錯誤(System and server-side errors),服務器不會拋出該錯誤,該錯誤也只是用來標識錯誤范圍的,即大于該錯誤值,且小于 ZAPIERROR 都是系統(tǒng)錯誤。

ZRUNTIMEINCONSISTENCY?

運行時非一致性錯誤。

ZDATAINCONSISTENCY?

數(shù)據(jù)非一致性錯誤。

ZCONNECTIONLOSS?

Zookeeper 客戶端與服務器端失去連接

ZMARSHALLINGERROR?

marshallingunmarshalling 數(shù)據(jù)時出現(xiàn)錯誤(Error while marshalling or unmarshalling data)

ZUNIMPLEMENTED?

該操作未實現(xiàn)(Operation is unimplemented)

ZOPERATIONTIMEOUT?

該操作超時(Operation timeout)

ZBADARGUMENTS?

非法參數(shù)錯誤(Invalid arguments)

ZINVALIDSTATE?

非法句柄狀態(tài)(Invliad zhandle state)

ZAPIERROR?

API 錯誤(API errors),服務器不會拋出該錯誤,該錯誤也只是用來標識錯誤范圍的,錯誤值大于該值的標識 API 錯誤,而小于該值的標識 ZSYSTEMERROR。

ZNONODE?

節(jié)點不存在(Node does not exist)

ZNOAUTH?

沒有經(jīng)過授權(Not authenticated)

ZBADVERSION?

版本沖突(Version conflict)

ZNOCHILDRENFOREPHEMERALS?

臨時節(jié)點不能擁有子節(jié)點(Ephemeral nodes may not have children)

ZNODEEXISTS?

節(jié)點已經(jīng)存在(The node already exists)

ZNOTEMPTY?

該節(jié)點具有自身的子節(jié)點(The node has children)

ZSESSIONEXPIRED?

會話過期(The session has been expired by the server)

ZINVALIDCALLBACK?

非法的回調函數(shù)(Invalid callback specified)

ZINVALIDACL?

非法的ACL(Invalid ACL specified)

ZAUTHFAILED?

客戶端授權失敗(Client authentication failed)

ZCLOSING?

Zookeeper 連接關閉(ZooKeeper is closing)

ZNOTHING?

并非錯誤,客戶端不需要處理服務器的響應(not error, no server responses to process)

ZSESSIONMOVED?

會話轉移至其他服務器,所以操作被忽略(session moved to another server, so operation is ignored)

?

至此,Zookeeper C API 中的大部分的常量和結構體均已介紹完畢,下一節(jié)《Zookeeper C API 指南三(回調函數(shù))》將介紹 Zookeeper C API 中的回調函數(shù)。

接上一篇《Zookeeper C API 指南二(監(jiān)視(Wathes), 基本常量和結構體介紹)》,本文重點介紹 Zookeeper C API 中的各種回調函數(shù)。

Zookeeper C API 中各種回調函數(shù)簡介

在具體介紹 Zookeeper C API 之前,首先介紹一下 Zookeeper C API 中的各種回調函數(shù)的原型:

監(jiān)視函數(shù)(watch function)原型

typedef void (*watcher_fn)(zhandle_t *zh, int type, int state, const char *path,void *watcherCtx);

?監(jiān)視函數(shù)原型的各個參數(shù)解釋如下:

zhzookeeper 句柄(handle)
type事件類型(event type). *_EVENT 常量之一.
state連接狀態(tài)(connection state). 狀態(tài)值為 *_STATE 常量之一.
path觸發(fā)監(jiān)視事件的 znode 節(jié)點的路徑,若為 NULL,則事件類型為 ZOO_SESSION_EVENT
watcherCtx監(jiān)視器上下文(watcher context).

其他回調函數(shù)的原型

Zookeeper 中還有幾種在異步 API(一般以 zoo_a*開頭的函數(shù)) 中使用的回調函數(shù),根據(jù)回調函數(shù)處理異步函數(shù)返回值類型的不同分為以下幾類:處理返回 void 類型的回調函數(shù),處理返回 Stat 結構的回調函數(shù),處理返回字符串的回調函數(shù),處理返回數(shù)據(jù)的回調函數(shù),處理返回字符串列表(a list of string)的回調函數(shù),同時處理返回字符串列表(a list of string)和 Stat 結構的回調函數(shù),以及處理返回 ACL 信息的回調函數(shù),它們分別如下:

// 處理返回 void 類型的回調函數(shù) typedef void(* void_completion_t)(int rc, const void *data);// 處理返回 Stat 結構的回調函數(shù) typedef void(* stat_completion_t)(int rc, const struct Stat *stat, const void *data); // 處理返回字符串的回調函數(shù) typedef void(* string_completion_t)(int rc, const char *value, const void *data); // 處理返回數(shù)據(jù)的回調函數(shù) typedef void(* data_completion_t)(int rc, const char *value, int value_len, const struct Stat *stat, const void *data); // 處理返回字符串列表(a list of string)的回調函數(shù) typedef void(* strings_completion_t)(int rc, const struct String_vector *strings, const void *data); // 同時處理返回字符串列表(a list of string)和 Stat 結構的回調函數(shù) typedef void(* strings_stat_completion_t)(int rc, const struct String_vector *strings, const struct Stat *stat, const void *data); // 處理以及返回 ACL 信息的回調函數(shù) typedef void(* acl_completion_t)(int rc, struct ACL_vector *acl, struct Stat *stat, const void *data);

?下面一一介紹上述幾種回調函數(shù)的用法:

  • 處理返回 void 類型的回調函數(shù)
typedef void(* void_completion_t)(int rc, const void *data)

該回調函數(shù)一般在異步 API 調用結束或 Zookeeper? 客戶端失去連接時被調用。

rc異步函數(shù)調用返回的錯誤碼,連接丟失/超時將觸發(fā)該原型函數(shù)(此處指具有該函數(shù)原型的回調函數(shù),下同)的調用,并且錯誤碼為 ZCONNECTIONLOSS --? Zookeeper 客戶端與服務器端的連接丟失,或者 ZOPERATIONTIMEOUT -- 連接超時;而與數(shù)據(jù)相關的事件也會觸發(fā)該原型函數(shù)的調用,同時置相應的錯誤碼,具體見后文(0 代異步函數(shù)調用成功)
data由調用者傳入指針,調用者可以通過該指針向回調函數(shù)傳入自定義的參數(shù),開發(fā)人員應負責此指針所指向內存的釋放。

?

  • 處理返回 Stat 結構的回調函數(shù)
typedef void(* stat_completion_t)(int rc, const struct Stat *stat, const void *data)

該函數(shù)一般在異步 API 調用結束或 Zookeeper? 客戶端失去連接時被調用。

rc異步函數(shù)調用返回的錯誤碼,連接丟失/超時將觸發(fā)該原型函數(shù)(此處指具有該函數(shù)原型的回調函數(shù),下同)的調用,并且錯誤碼為 ZCONNECTIONLOSS --? Zookeeper 客戶端與服務器端的連接丟失,或者 ZOPERATIONTIMEOUT -- 連接超時;而與數(shù)據(jù)相關的事件也會觸發(fā)該原型函數(shù)的調用,同時置相應的錯誤碼,具體見后文(0 代異步函數(shù)調用成功)
stat指向與該 znode 節(jié)點相關的 Stat 信息,如果返回非 0 值(即異步調用函數(shù)出錯),stat 所指向的區(qū)域是未定義的,開發(fā)者不負責釋放 stat 所指向的內存空間。
data由調用者傳入指針,調用者可以通過該指針向回調函數(shù)傳入自定義的參數(shù),開發(fā)人員應負責此指針所指向內存的釋放。

?

  • 處理返回字符串的回調函數(shù)
typedef void(* string_completion_t)(int rc, const char *value, const void *data)

該函數(shù)一般在異步 API 調用結束或 Zookeeper? 客戶端失去連接時被調用。

rc異步函數(shù)調用返回的錯誤碼,連接丟失/超時將觸發(fā)該原型函數(shù)(此處指具有該函數(shù)原型的回調函數(shù),下同)的調用,并且錯誤碼為 ZCONNECTIONLOSS --? Zookeeper 客戶端與服務器端的連接丟失,或者 ZOPERATIONTIMEOUT -- 連接超時;而與數(shù)據(jù)相關的事件也會觸發(fā)該原型函數(shù)的調用,同時置相應的錯誤碼,具體見后文(0 代異步函數(shù)調用成功)
value返回的字符串
data由調用者傳入指針,調用者可以通過該指針向回調函數(shù)傳入自定義的參數(shù),開發(fā)人員應負責此指針所指向內存的釋放。

?

  • 處理返回數(shù)據(jù)的回調函數(shù)
typedef void(* data_completion_t)(int rc, const char *value, int value_len, const struct Stat *stat, const void *data)

該函數(shù)一般在異步 API 調用結束或 Zookeeper? 客戶端失去連接時被調用。

rc異步函數(shù)調用返回的錯誤碼,連接丟失/超時將觸發(fā)該原型函數(shù)(此處指具有該函數(shù)原型的回調函數(shù),下同)的調用,并且錯誤碼為 ZCONNECTIONLOSS --? Zookeeper 客戶端與服務器端的連接丟失,或者 ZOPERATIONTIMEOUT -- 連接超時;而與數(shù)據(jù)相關的事件也會觸發(fā)該原型函數(shù)的調用,同時置相應的錯誤碼,具體見后文(0 代異步函數(shù)調用成功)
value異步調用的返回值,如果返回非 0 值(即異步調用函數(shù)出錯),value 所指向的區(qū)域是未定義的,開發(fā)者不負責釋放?value 所指向的內存空間。
value_len返回 value 數(shù)據(jù)字節(jié)數(shù)(bytes)
stat指向與該 znode 節(jié)點相關的 Stat 信息,如果返回非 0 值(即異步調用函數(shù)出錯),stat 所指向的區(qū)域是未定義的,開發(fā)者不負責釋放 stat 所指向的內存空間。
data由調用者傳入指針,調用者可以通過該指針向回調函數(shù)傳入自定義的參數(shù),開發(fā)人員應負責此指針所指向內存的釋放。

?

  • 處理返回字符串列表(a list of string)的回調函數(shù)
typedef void(* strings_completion_t)(int rc, const struct String_vector *strings, const void *data)

該函數(shù)一般在異步 API 調用結束或 Zookeeper? 客戶端失去連接時被調用。

rc異步函數(shù)調用返回的錯誤碼,連接丟失/超時將觸發(fā)該原型函數(shù)(此處指具有該函數(shù)原型的回調函數(shù),下同)的調用,并且錯誤碼為 ZCONNECTIONLOSS --? Zookeeper 客戶端與服務器端的連接丟失,或者 ZOPERATIONTIMEOUT -- 連接超時;而與數(shù)據(jù)相關的事件也會觸發(fā)該原型函數(shù)的調用,同時置相應的錯誤碼,具體見后文(0 代異步函數(shù)調用成功)
strings指向包含了某 znode 節(jié)點的所有子節(jié)點名稱列表的結構,如果返回非 0 值(即異步調用函數(shù)出錯),strings 所指向的區(qū)域是未定義的,開發(fā)者不負責釋放strings 所指向的內存空間。
data由調用者傳入指針,調用者可以通過該指針向回調函數(shù)傳入自定義的參數(shù),開發(fā)人員應負責此指針所指向內存的釋放。

?

  • 同時處理返回字符串列表(a list of string)和 Stat 結構的回調函數(shù)
typedef void(* strings_stat_completion_t)(int rc, const struct String_vector *strings, const struct Stat *stat, const void *data)

該函數(shù)一般在異步 API 調用結束或 Zookeeper? 客戶端失去連接時被調用。

rc異步函數(shù)調用返回的錯誤碼,連接丟失/超時將觸發(fā)該原型函數(shù)(此處指具有該函數(shù)原型的回調函數(shù),下同)的調用,并且錯誤碼為 ZCONNECTIONLOSS --? Zookeeper 客戶端與服務器端的連接丟失,或者 ZOPERATIONTIMEOUT -- 連接超時;而與數(shù)據(jù)相關的事件也會觸發(fā)該原型函數(shù)的調用,同時置相應的錯誤碼,具體見后文(0 代異步函數(shù)調用成功)
strings指向包含了某 znode 節(jié)點的所有子節(jié)點名稱列表的結構,如果返回非 0 值(即異步調用函數(shù)出錯),strings 所指向的區(qū)域是未定義的,開發(fā)者不負責釋放strings 所指向的內存空間。
stat指向與該 znode 節(jié)點相關的 Stat 信息,如果返回非 0 值(即異步調用函數(shù)出錯),stat 所指向的區(qū)域是未定義的,開發(fā)者不負責釋放 stat 所指向的內存空間。
data由調用者傳入的指針,調用者可以通過該指針向回調函數(shù)傳入自定義的參數(shù),開發(fā)人員應負責此指針所指向內存的釋放。

?

  • 處理返回 ACL 信息的回調函數(shù)
typedef void(* acl_completion_t)(int rc, struct ACL_vector *acl, struct Stat *stat, const void *data)

該函數(shù)一般在異步 API 調用結束或 Zookeeper? 客戶端失去連接時被調用。

rc異步函數(shù)調用返回的錯誤碼,連接丟失/超時將觸發(fā)該原型函數(shù)(此處指具有該函數(shù)原型的回調函數(shù),下同)的調用,并且錯誤碼為 ZCONNECTIONLOSS --? Zookeeper 客戶端與服務器端的連接丟失,或者 ZOPERATIONTIMEOUT -- 連接超時;而與數(shù)據(jù)相關的事件也會觸發(fā)該原型函數(shù)的調用,同時置相應的錯誤碼,具體見后文(0 代異步函數(shù)調用成功)
acl指向包含某 znode 節(jié)點 ACL 信息的指針,如果返回非 0 值(即異步調用函數(shù)出錯),acl 所指向的區(qū)域是未定義的,開發(fā)者不負責釋放 acl 所指向的內存空間。
stat指向與該 znode 節(jié)點相關的 Stat 信息,如果返回非 0 值(即異步調用函數(shù)出錯),stat 所指向的區(qū)域是未定義的,開發(fā)者不負責釋放 stat 所指向的內存空間。
data由調用者傳入的指針,調用者可以通過該指針向回調函數(shù)傳入自定義的參數(shù),開發(fā)人員應負責此指針所指向內存的釋放。

?

至此,所有的回調函數(shù)均已介紹完畢,下一節(jié)將介紹 Zookeeper C API 分類和基本 API 的使用,見第四講《Zookeeper C API 指南四(C API 概覽)》

上一節(jié)《Zookeeper C API 指南三(回調函數(shù))》重點講了 Zookeeper C API 中各種回調函數(shù)的原型,本節(jié)將切入正題,正式講解 Zookeeper C API。相信大家讀完本文后應該對 Zookeeper C API 的使用有一個比較清晰的認識。

Zookeeper C API 概覽

Zookeeper C API 很規(guī)范,接口很容易記憶,大部分接口均以 zoo_ 開頭,只有少量接口以 zookeeper_ 開頭,所有的 API 匯總如下:

void zoo_create_op_init(zoo_op_t * op, const char *path, const char *value,int valuelen, const struct ACL_vector *acl,int flags, char *path_buffer, int path_buffer_len);void zoo_delete_op_init(zoo_op_t * op, const char *path, int version);void zoo_set_op_init(zoo_op_t * op, const char *path,const char *buffer, int buflen, int version,struct Stat *stat);void zoo_check_op_init(zoo_op_t * op, const char *path, int version);ZOOAPI zhandle_t *zookeeper_init(const char *host, watcher_fn fn,int recv_timeout,const clientid_t * clientid,void *context, int flags);ZOOAPI int zookeeper_close(zhandle_t * zh);ZOOAPI const clientid_t *zoo_client_id(zhandle_t * zh);ZOOAPI int zoo_recv_timeout(zhandle_t * zh);ZOOAPI const void *zoo_get_context(zhandle_t * zh);ZOOAPI void zoo_set_context(zhandle_t * zh, void *context);ZOOAPI watcher_fn zoo_set_watcher(zhandle_t * zh, watcher_fn newFn);ZOOAPI struct sockaddr *zookeeper_get_connected_host(zhandle_t * zh, struct sockaddr*addr,socklen_t * addr_len);ZOOAPI int zookeeper_interest(zhandle_t * zh, int *fd, int *interest,struct timeval *tv);ZOOAPI int zookeeper_process(zhandle_t * zh, int events);ZOOAPI int zoo_state(zhandle_t * zh);ZOOAPI int zoo_acreate(zhandle_t * zh, const char *path,const char *value, int valuelen,const struct ACL_vector *acl, int flags,string_completion_t completion, const void *data);ZOOAPI int zoo_adelete(zhandle_t * zh, const char *path, int version,void_completion_t completion, const void *data);ZOOAPI int zoo_aexists(zhandle_t * zh, const char *path, int watch,stat_completion_t completion, const void *data);ZOOAPI int zoo_awexists(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,stat_completion_t completion, const void *data);ZOOAPI int zoo_aget(zhandle_t * zh, const char *path, int watch,data_completion_t completion, const void *data);ZOOAPI int zoo_awget(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,data_completion_t completion, const void *data);ZOOAPI int zoo_aset(zhandle_t * zh, const char *path,const char *buffer, int buflen, int version,stat_completion_t completion, const void *data);ZOOAPI int zoo_aget_children(zhandle_t * zh, const char *path,int watch,strings_completion_t completion,const void *data);ZOOAPI int zoo_awget_children(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,strings_completion_t completion,const void *data);ZOOAPI int zoo_aget_children2(zhandle_t * zh, const char *path,int watch,strings_stat_completion_t completion,const void *data);ZOOAPI int zoo_awget_children2(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,strings_stat_completion_t completion,const void *data);ZOOAPI int zoo_async(zhandle_t * zh, const char *path,string_completion_t completion, const void *data);ZOOAPI int zoo_aget_acl(zhandle_t * zh, const char *path,acl_completion_t completion, const void *data);ZOOAPI int zoo_aset_acl(zhandle_t * zh, const char *path, int version,struct ACL_vector *acl, void_completion_t,const void *data);ZOOAPI int zoo_amulti(zhandle_t * zh, int count, const zoo_op_t * ops,zoo_op_result_t * results, void_completion_t,const void *data);ZOOAPI const char *zerror(int c);ZOOAPI int zoo_add_auth(zhandle_t * zh, const char *scheme,const char *cert, int certLen,void_completion_t completion, const void *data);ZOOAPI int is_unrecoverable(zhandle_t * zh);ZOOAPI void zoo_set_debug_level(ZooLogLevel logLevel);ZOOAPI void zoo_set_log_stream(FILE * logStream);ZOOAPI void zoo_deterministic_conn_order(int yesOrNo);ZOOAPI int zoo_create(zhandle_t * zh, const char *path,const char *value, int valuelen,const struct ACL_vector *acl, int flags,char *path_buffer, int path_buffer_len);ZOOAPI int zoo_delete(zhandle_t * zh, const char *path, int version);ZOOAPI int zoo_exists(zhandle_t * zh, const char *path, int watch,struct Stat *stat);ZOOAPI int zoo_wexists(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct Stat *stat);ZOOAPI int zoo_get(zhandle_t * zh, const char *path, int watch,char *buffer, int *buffer_len, struct Stat *stat);ZOOAPI int zoo_wget(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,char *buffer, int *buffer_len, struct Stat *stat);ZOOAPI int zoo_set(zhandle_t * zh, const char *path,const char *buffer, int buflen, int version);ZOOAPI int zoo_set2(zhandle_t * zh, const char *path,const char *buffer, int buflen, int version,struct Stat *stat);ZOOAPI int zoo_get_children(zhandle_t * zh, const char *path,int watch, struct String_vector *strings);ZOOAPI int zoo_wget_children(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct String_vector *strings);ZOOAPI int zoo_get_children2(zhandle_t * zh, const char *path,int watch, struct String_vector *strings,struct Stat *stat);ZOOAPI int zoo_wget_children2(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct String_vector *strings,struct Stat *stat);ZOOAPI int zoo_get_acl(zhandle_t * zh, const char *path,struct ACL_vector *acl, struct Stat *stat);ZOOAPI int zoo_set_acl(zhandle_t * zh, const char *path, int version,const struct ACL_vector *acl);ZOOAPI int zoo_multi(zhandle_t * zh, int count, const zoo_op_t * ops,zoo_op_result_t * results);

除了基本的初始化、銷毀 Zookeeper 句柄(zhandle),設置日志等級、日志流以及一些具有輔助功能 API(zerror(), zoo_state()等) 外,Zookeeper C API 大部分接口可以根據(jù)同步和異步特性分為兩類,同步接口以 zoo_* 開頭,異步接口以則以 zoo_a* 開頭。并且除了 zookeeper_init() 以及與 zoo_multi() 或 zoo_amulti() 批量操作相關的 zoo_op_t 初始化外,其他的 API 的第一個參數(shù)均為 zhandle_t * zh, 即 Zookeeper 句柄的指針。

Zookeeper C API 分類

  • 初始化、銷毀 Zookeeper 句柄
ZOOAPI zhandle_t *zookeeper_init(const char *host, watcher_fn fn,int recv_timeout,const clientid_t * clientid,void *context, int flags);ZOOAPI int zookeeper_close(zhandle_t * zh);
  • 輔助函數(shù)
// 設置日志等級、日志流 ZOOAPI void zoo_set_debug_level(ZooLogLevel logLevel); ZOOAPI void zoo_set_log_stream(FILE * logStream);ZOOAPI const clientid_t *zoo_client_id(zhandle_t * zh);ZOOAPI int zoo_recv_timeout(zhandle_t * zh);ZOOAPI const void *zoo_get_context(zhandle_t * zh);ZOOAPI void zoo_set_context(zhandle_t * zh, void *context);ZOOAPI watcher_fn zoo_set_watcher(zhandle_t * zh, watcher_fn newFn);ZOOAPI struct sockaddr *zookeeper_get_connected_host(zhandle_t * zh, struct sockaddr*addr,socklen_t * addr_len);ZOOAPI int zookeeper_interest(zhandle_t * zh, int *fd, int *interest,struct timeval *tv);ZOOAPI int zookeeper_process(zhandle_t * zh, int events);ZOOAPI int zoo_state(zhandle_t * zh);ZOOAPI const char *zerror(int c);ZOOAPI int is_unrecoverable(zhandle_t * zh);ZOOAPI void zoo_deterministic_conn_order(int yesOrNo);
  • 與 zoo_multi() 和 zoo_amulti() 批量操作相關的 zoo_op_t 初始化
void zoo_create_op_init(zoo_op_t * op, const char *path, const char *value,int valuelen, const struct ACL_vector *acl,int flags, char *path_buffer, int path_buffer_len);void zoo_delete_op_init(zoo_op_t * op, const char *path, int version);void zoo_set_op_init(zoo_op_t * op, const char *path,const char *buffer, int buflen, int version,struct Stat *stat);void zoo_check_op_init(zoo_op_t * op, const char *path, int version);
  • Zookeeper C API 同步接口
ZOOAPI int zoo_add_auth(zhandle_t * zh, const char *scheme,const char *cert, int certLen,void_completion_t completion, const void *data);ZOOAPI int zoo_create(zhandle_t * zh, const char *path,const char *value, int valuelen,const struct ACL_vector *acl, int flags,char *path_buffer, int path_buffer_len);ZOOAPI int zoo_delete(zhandle_t * zh, const char *path, int version);ZOOAPI int zoo_exists(zhandle_t * zh, const char *path, int watch,struct Stat *stat);ZOOAPI int zoo_wexists(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct Stat *stat);ZOOAPI int zoo_get(zhandle_t * zh, const char *path, int watch,char *buffer, int *buffer_len, struct Stat *stat);ZOOAPI int zoo_wget(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,char *buffer, int *buffer_len, struct Stat *stat);ZOOAPI int zoo_set(zhandle_t * zh, const char *path,const char *buffer, int buflen, int version);ZOOAPI int zoo_set2(zhandle_t * zh, const char *path,const char *buffer, int buflen, int version,struct Stat *stat);ZOOAPI int zoo_get_children(zhandle_t * zh, const char *path,int watch, struct String_vector *strings);ZOOAPI int zoo_wget_children(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct String_vector *strings);ZOOAPI int zoo_get_children2(zhandle_t * zh, const char *path,int watch, struct String_vector *strings,struct Stat *stat);ZOOAPI int zoo_wget_children2(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct String_vector *strings,struct Stat *stat);ZOOAPI int zoo_get_acl(zhandle_t * zh, const char *path,struct ACL_vector *acl, struct Stat *stat);ZOOAPI int zoo_set_acl(zhandle_t * zh, const char *path, int version,const struct ACL_vector *acl);ZOOAPI int zoo_multi(zhandle_t * zh, int count, const zoo_op_t * ops,zoo_op_result_t * results);
  • Zookeeper C API 異步接口
ZOOAPI int zoo_acreate(zhandle_t * zh, const char *path,const char *value, int valuelen,const struct ACL_vector *acl, int flags,string_completion_t completion, const void *data);ZOOAPI int zoo_adelete(zhandle_t * zh, const char *path, int version,void_completion_t completion, const void *data);ZOOAPI int zoo_aexists(zhandle_t * zh, const char *path, int watch,stat_completion_t completion, const void *data);ZOOAPI int zoo_awexists(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,stat_completion_t completion, const void *data);ZOOAPI int zoo_aget(zhandle_t * zh, const char *path, int watch,data_completion_t completion, const void *data);ZOOAPI int zoo_awget(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,data_completion_t completion, const void *data);ZOOAPI int zoo_aset(zhandle_t * zh, const char *path,const char *buffer, int buflen, int version,stat_completion_t completion, const void *data);ZOOAPI int zoo_aget_children(zhandle_t * zh, const char *path,int watch,strings_completion_t completion,const void *data);ZOOAPI int zoo_awget_children(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,strings_completion_t completion,const void *data);ZOOAPI int zoo_aget_children2(zhandle_t * zh, const char *path,int watch,strings_stat_completion_t completion,const void *data);ZOOAPI int zoo_awget_children2(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,strings_stat_completion_t completion,const void *data);ZOOAPI int zoo_async(zhandle_t * zh, const char *path,string_completion_t completion, const void *data);ZOOAPI int zoo_aget_acl(zhandle_t * zh, const char *path,acl_completion_t completion, const void *data);ZOOAPI int zoo_aset_acl(zhandle_t * zh, const char *path, int version,struct ACL_vector *acl, void_completion_t,const void *data);ZOOAPI int zoo_amulti(zhandle_t * zh, int count, const zoo_op_t * ops,zoo_op_result_t * results, void_completion_t,const void *data);

?Zookeeper C API 初體驗

有了上面的介紹,下面我們來看一看如何使簡單地使用 Zookeeper C API 吧。

在使用 Zookeeper C API 時應注意:

  • 頭文件包含 #include <zookeeper/zookeeper.h>
  • 如果你需要編譯多線程版本客戶端程序,請?zhí)砑泳幾g選項 -DTHREADED,同時鏈接時應鏈接?zookeeper_mt 庫;如果你需要編譯單線程客戶端程序,請不要添加編譯選項 -DTHREADED,同時鏈接時應鏈接?zookeeper_st 庫。

一個基本的程序如下(更詳細的例子可以參看 src/c/src/cli.c):

/** =============================================================================** Filename: zktest.c** Description: zookeeper api testcase.** Created: 02/15/2013 08:48:49 PM** Author: Fu Haiping (forhappy), haipingf@gmail.com* Company: ICT ( Institute Of Computing Technology, CAS )** =============================================================================*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <zookeeper/zookeeper.h> #include <zookeeper/zookeeper_log.h>void zktest_watcher_g(zhandle_t* zh, int type, int state,const char* path, void* watcherCtx) {printf("Something happened.\n");printf("type: %d\n", type);printf("state: %d\n", state);printf("path: %s\n", path);printf("watcherCtx: %s\n", (char *)watcherCtx); }void zktest_dump_stat(const struct Stat *stat) {char tctimes[40];char tmtimes[40];time_t tctime;time_t tmtime;if (!stat) {fprintf(stderr,"null\n");return;}tctime = stat->ctime/1000;tmtime = stat->mtime/1000;ctime_r(&tmtime, tmtimes);ctime_r(&tctime, tctimes);fprintf(stderr, "\tctime = %s\tczxid=%llx\n""\tmtime=%s\tmzxid=%llx\n""\tversion=%x\taversion=%x\n""\tephemeralOwner = %llx\n",tctimes, stat->czxid,tmtimes, stat->mzxid,(unsigned int)stat->version, (unsigned int)stat->aversion,stat->ephemeralOwner); }void zktest_stat_completion(int rc, const struct Stat *stat, const void *data) {fprintf(stderr, "%s: rc = %d Stat:\n", (char*)data, rc);zktest_dump_stat(stat); }void zktest_void_completion(int rc, const void *data) {fprintf(stderr, "[%s]: rc = %d\n", (char*)(data==0?"null":data), rc); }void zktest_string_completion(int rc, const char *name, const void *data) {fprintf(stderr, "[%s]: rc = %d\n", (char*)(data==0?"null":data), rc);if (!rc) {fprintf(stderr, "\tname = %s\n", name);} }int main(int argc, const char *argv[]) {const char* host = "127.0.0.1:2181,127.0.0.1:2182,""127.0.0.1:2183,127.0.0.1:2184,127.0.0.1:2185";int timeout = 30000;zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);zhandle_t* zkhandle = zookeeper_init(host,zktest_watcher_g, timeout, 0, "hello zookeeper.", 0);if (zkhandle == NULL) {fprintf(stderr, "Error when connecting to zookeeper servers...\n");exit(EXIT_FAILURE);}// struct ACL ALL_ACL[] = {{ZOO_PERM_ALL, ZOO_ANYONE_ID_UNSAFE}};// struct ACL_vector ALL_PERMS = {1, ALL_ACL};int ret = zoo_acreate(zkhandle, "/xyz", "hello", 5,&ZOO_OPEN_ACL_UNSAFE, 0 /* ZOO_SEQUENCE */,zktest_string_completion, "acreate");if (ret) {fprintf(stderr, "Error %d for %s\n", ret, "acreate");exit(EXIT_FAILURE);}ret = 0;ret = zoo_aexists(zkhandle, "/xyz", 1, zktest_stat_completion, "aexists");if (ret) {fprintf(stderr, "Error %d for %s\n", ret, "aexists");exit(EXIT_FAILURE);}ret = 0;// Wait for asynchronous zookeeper call done. getchar();ret = zoo_adelete(zkhandle, "/xyz", -1, zktest_void_completion, "adelete");if (ret) {fprintf(stderr, "Error %d for %s\n", ret, "adelete");exit(EXIT_FAILURE);}// Wait for asynchronous zookeeper call done. getchar();zookeeper_close(zkhandle); }

下面簡單講講這個程序的結構:

  • 首先聲明 host, timeout 變量。
const char* host = "127.0.0.1:2181,127.0.0.1:2182,""127.0.0.1:2183,127.0.0.1:2184,127.0.0.1:2185"; int timeout = 30000;

其中 host 字符串格式為逗號隔開的 IP:PORT對,可以是 Zookeeper 集群中的全部或部分 Zookeeper 實例的 IP:PORT對,我們在第一講《準備工作》中介紹了如何部署一個偽分布式的集群,上述的 host 就是這些 zookeeper 實例的IP:PORT對。

另外 timeout 是 Zookeeper 客戶端連接服務器的超時時間,單位為毫秒,timeout = 30000 說明如果 30 秒內客戶端沒有連接上 Zookeeper 服務則表示連接超時。

  • 設置日志等級。
zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);
  • 初始化 Zookeeper 句柄(zhandle_t)。
zhandle_t* zkhandle = zookeeper_init(host,zktest_watcher_g, timeout, 0, "hello zookeeper.", 0);if (zkhandle == NULL) {fprintf(stderr, "Error when connecting to zookeeper servers...\n");exit(EXIT_FAILURE);}

初始化 Zookeeper 句柄 zookeeper_init() 函數(shù)原型如下:

ZOOAPI zhandle_t *zookeeper_init(const char *host, watcher_fn fn,int recv_timeout,const clientid_t * clientid,void *context, int flags);

各個參數(shù)解釋如下:

host逗號隔開的 host:port 對, 每個代表一個 zk server, 例如: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002"
fn全局的監(jiān)視器回調函數(shù),當發(fā)生事件通知時,該函數(shù)會被調用。
clientid客戶端嘗試重連的先前會話的ID,如果不需要重連先前的會話,則設置為 0。客戶端可以通過調用 zoo_client_id來訪問一個已經(jīng)連接上的并且有效的會話ID,如果clientid對應的會話超時,或者由于某種原因 clientid變?yōu)闊o效了,那么zookeeper_init 將返回一個非法的zhandle_t, 通過 zhandle_t 的狀態(tài)可以獲知zookeeper_init 調用失敗的原因。 (通常為 ZOO_EXPIRED_SESSION_STATE).
context與 zhandle_t 實例相關聯(lián)的“上下文對象”(可以通過該參數(shù)為 zhandle_t 傳入自定義類型的數(shù)據(jù)),應用程序可以通過 zoo_get_context訪問它(例如在監(jiān)視器回調函數(shù)中),當然 zookeeper 內部沒有用到該參數(shù),所以 context 可以設置為 NULL。
flags目前為保留參數(shù),設置為 0。
  • 創(chuàng)建一個 znode 節(jié)點。
// struct ACL ALL_ACL[] = {{ZOO_PERM_ALL, ZOO_ANYONE_ID_UNSAFE}};// struct ACL_vector ALL_PERMS = {1, ALL_ACL};int ret = zoo_acreate(zkhandle, "/xyz", "hello", 5,&ZOO_OPEN_ACL_UNSAFE, 0 /* ZOO_SEQUENCE */,zktest_string_completion, "acreate");if (ret) {fprintf(stderr, "Error %d for %s\n", ret, "acreate");exit(EXIT_FAILURE);}

這里采用異步方式創(chuàng)建 znode 節(jié)點,zoo_acreate() 函數(shù)原型為:

ZOOAPI int zoo_acreate(zhandle_t * zh, const char *path,const char *value, int valuelen,const struct ACL_vector *acl, int flags,string_completion_t completion, const void *data);

各個參數(shù)解釋如下:

zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
value該節(jié)點保存的數(shù)據(jù)。
valuelen該節(jié)點保存數(shù)據(jù)的大小。
acl該節(jié)點初始 ACL,ACL 不能為null 或空。
flags該參數(shù)可以設置為 0,或者創(chuàng)建標識符 ZOO_EPHEMERAL,?ZOO_SEQUENCE 的組合或(OR)。
completion當創(chuàng)建節(jié)點請求完成時會調用該函數(shù),該函數(shù)原型詳見第三講《回調函數(shù)》一節(jié)。同時傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 父節(jié)點不存在;ZNODEEXISTS 節(jié)點已存在;ZNOAUTH 客戶端沒有權限創(chuàng)建節(jié)點。ZNOCHILDRENFOREPHEMERALS 臨時節(jié)點不能創(chuàng)建子節(jié)點。
datacompletino函數(shù)被調用時,傳遞給 completion 的數(shù)據(jù)。
  • 調用 exists() 函數(shù),設置監(jiān)視器。
ret = zoo_aexists(zkhandle, "/xyz", 1, zktest_stat_completion, "aexists");if (ret) {fprintf(stderr, "Error %d for %s\n", ret, "aexists");exit(EXIT_FAILURE);}
  • 調用 delete 函數(shù),刪除 znode 節(jié)點。
ret = zoo_adelete(zkhandle, "/xyz", -1, zktest_void_completion, "adelete");if (ret) {fprintf(stderr, "Error %d for %s\n", ret, "adelete");exit(EXIT_FAILURE);}
  • 銷毀 zookeeper 句柄
zookeeper_close(zkhandle);

好了,至此本文大致講完了 Zookeeper C API 的分類和幾個基本函數(shù)的用法。之所以為 Zookeeper C API 分類是方便記憶,開發(fā)者可以迅速找到自己需要的 API;另外,本文還講了幾個基本函數(shù)的使用方法,包括 zookeeper_init(),zoo_acreate(), zoo_aexists(), zoo_adelete() 以及 zookeeper_close()。相信大家對 Zookeeper C API 也有了一個大致的了解,第五講我會給大家介紹 Zookeeper C API 中的同步調用的函數(shù)(即以 zoo_* 開頭的函數(shù)),然后第六講給大家介紹 Zookeeper C API 中的異步調用的函數(shù)(即以 zoo_a* 開頭的函數(shù))。

上一講《Zookeeper C API 指南四(C API 概覽)》講了Zookeeper C API 的分類和幾個基本函數(shù)的用法,相信大家對 Zookeeper C API 也有了一個大致的了解,本文我會給大家介紹 Zookeeper C API 中的同步調用的函數(shù)(即以 zoo_* 開頭的函數(shù))。

Zookeeper C API 中與訪問 Zookeeper 服務相關(比如創(chuàng)建、刪除 znode 節(jié)點,獲取子節(jié)點,設置 znode 數(shù)據(jù)等)的同步 API 如下:

ZOOAPI int zoo_add_auth(zhandle_t * zh, const char *scheme,const char *cert, int certLen,void_completion_t completion, const void *data);ZOOAPI int zoo_create(zhandle_t * zh, const char *path,const char *value, int valuelen,const struct ACL_vector *acl, int flags,char *path_buffer, int path_buffer_len);ZOOAPI int zoo_delete(zhandle_t * zh, const char *path, int version);ZOOAPI int zoo_exists(zhandle_t * zh, const char *path, int watch,struct Stat *stat);ZOOAPI int zoo_wexists(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct Stat *stat);ZOOAPI int zoo_get(zhandle_t * zh, const char *path, int watch,char *buffer, int *buffer_len, struct Stat *stat);ZOOAPI int zoo_wget(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,char *buffer, int *buffer_len, struct Stat *stat);ZOOAPI int zoo_set(zhandle_t * zh, const char *path,const char *buffer, int buflen, int version);ZOOAPI int zoo_set2(zhandle_t * zh, const char *path,const char *buffer, int buflen, int version,struct Stat *stat);ZOOAPI int zoo_get_children(zhandle_t * zh, const char *path,int watch, struct String_vector *strings);ZOOAPI int zoo_wget_children(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct String_vector *strings);ZOOAPI int zoo_get_children2(zhandle_t * zh, const char *path,int watch, struct String_vector *strings,struct Stat *stat);ZOOAPI int zoo_wget_children2(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct String_vector *strings,struct Stat *stat);ZOOAPI int zoo_get_acl(zhandle_t * zh, const char *path,struct ACL_vector *acl, struct Stat *stat);ZOOAPI int zoo_set_acl(zhandle_t * zh, const char *path, int version,const struct ACL_vector *acl);ZOOAPI int zoo_multi(zhandle_t * zh, int count, const zoo_op_t * ops,zoo_op_result_t * results);

本文將以上同步 API 在此細分為一下幾類:(1). 創(chuàng)建、刪除 znode 節(jié)點,(2). 可設置 watch 的 API,(3). 訪問、設置節(jié)點 ACL 的 API,(4). 批處理 API

  • 創(chuàng)建、刪除 znode 節(jié)點(兩個)
ZOOAPI int zoo_create(zhandle_t * zh, const char *path,const char *value, int valuelen,const struct ACL_vector *acl, int flags,char *path_buffer, int path_buffer_len);ZOOAPI int zoo_delete(zhandle_t * zh, const char *path, int version);
  • 創(chuàng)建 znode 節(jié)點:
ZOOAPI int zoo_create(zhandle_t * zh, const char *path,const char *value, int valuelen,const struct ACL_vector *acl, int flags,char *path_buffer, int path_buffer_len);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
value該節(jié)點保存的數(shù)據(jù)。
valuelen該節(jié)點保存數(shù)據(jù)的大小。如果 value 被設置為 NULL(該 znode 節(jié)點不包含數(shù)據(jù)),則 valuelen 應該設置為 -1。
acl該節(jié)點初始 ACL,ACL 不能為null 或空。
flags該參數(shù)可以設置為 0,或者創(chuàng)建標識符ZOO_EPHEMERAL,?ZOO_SEQUENCE 的組合或(OR)。
path_buffer用于保存返回節(jié)點新路徑(因為設置了ZOO_SEQUENCE 后 zoo_create 所創(chuàng)建的節(jié)點名稱與參數(shù) path 提供的名稱不同,新的節(jié)點名稱后面填充了序號),path 字符串以 NULL 結束。path_buffer 可以設置為 NULL,此時 path_buffer_len 等于 0。
path_buffer_lenpath_buffer 的長度,如果新節(jié)點名稱的長度大于path_buffer_len,則節(jié)點名稱將會被截斷,而服務器端該節(jié)點的名稱不會截斷。
  • 刪除 znode 節(jié)點:
ZOOAPI int zoo_delete(zhandle_t * zh, const char *path, int version);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
version節(jié)點的版本號,如果該 znode 節(jié)點的實際版本號與該參數(shù)提供的版本號不一值,則刪除節(jié)點失敗,如果 version 為 -1,則不作版本檢查。

?

  • 可設置 watch 的 API(exists(兩個) + get(兩個) + get_children(四個) = 八個)
ZOOAPI int zoo_exists(zhandle_t * zh, const char *path, int watch,struct Stat *stat);ZOOAPI int zoo_wexists(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct Stat *stat);ZOOAPI int zoo_get(zhandle_t * zh, const char *path, int watch,char *buffer, int *buffer_len, struct Stat *stat);ZOOAPI int zoo_wget(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,char *buffer, int *buffer_len, struct Stat *stat);ZOOAPI int zoo_get_children(zhandle_t * zh, const char *path,int watch, struct String_vector *strings);ZOOAPI int zoo_wget_children(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct String_vector *strings);ZOOAPI int zoo_get_children2(zhandle_t * zh, const char *path,int watch, struct String_vector *strings,struct Stat *stat);ZOOAPI int zoo_wget_children2(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct String_vector *strings,struct Stat *stat);
  • 檢查節(jié)點狀態(tài) exists(兩個,分別是 zoo_exists() 和 zoo_wexists(),區(qū)別是后者可以指定單獨的 watcher_fn(監(jiān)視器回調函數(shù)),而前者只能用 zookeeper_init() 設置的全局監(jiān)視器回調函數(shù),同時 get 和 get_children兩族函數(shù)也一樣,帶有zoo_w* 的函數(shù)可以指定單獨的 watcher_fn)。
ZOOAPI int zoo_exists(zhandle_t * zh, const char *path, int watch, struct Stat *stat);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
watch如果非 0,則在服務器端設置監(jiān)視,當節(jié)點發(fā)生變化時客戶端會得到通知,即使當前指定的節(jié)點不存在也會設置監(jiān)視,這樣該節(jié)點被創(chuàng)建時,客戶端也可以得到通知。
stat返回的 Stat 信息。

?

ZOOAPI int zoo_wexists(zhandle_t * zh, const char *path, watcher_fn watcher, void *watcherCtx,struct Stat *stat);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
watcher如果不為 NULL 則會在服務器端設置監(jiān)視,當節(jié)點發(fā)生變化時客戶端會得到通知,即使當前指定的節(jié)點不存在也會設置監(jiān)視,這樣該節(jié)點被創(chuàng)建時,客戶端也可以得到通知。
watcherCtx用戶指定的數(shù)據(jù),將被傳入到監(jiān)視器回調函數(shù)中,與由 zookeeper_init() 設置的全局監(jiān)視器上下文不同,該函數(shù)設置的監(jiān)視器上下文只與當前的監(jiān)視器相關聯(lián)。
stat返回的 Stat 信息。

?

  • 獲取節(jié)點數(shù)據(jù) get(兩個)
ZOOAPI int zoo_get(zhandle_t * zh, const char *path, int watch,char *buffer, int *buffer_len, struct Stat *stat);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
watch如果非0,則在服務器端設置監(jiān)視,當節(jié)點發(fā)生變化時客戶端會得到通知
buffer用于保存從 zookeeper 服務器獲取的節(jié)點數(shù)據(jù)。
buffer_lenbuffer 大小,一旦成功返回該值將會被設置為節(jié)點數(shù)據(jù)的實際大小,如果節(jié)點的數(shù)據(jù)為空,則數(shù)據(jù)大小為 -1,buffer_len 也為 -1。
stat如果非空,stat 指向的結構將會保存該節(jié)點的 Stat 信息。

?

ZOOAPI int zoo_wget(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,char *buffer, int *buffer_len, struct Stat *stat);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
watcher如果不為 NULL 則會在服務器端設置監(jiān)視,當節(jié)點發(fā)生變化時客戶端會得到通知
watcherCtx用戶指定的數(shù)據(jù),將被傳入到監(jiān)視器回調函數(shù)中,與由 zookeeper_init() 設置的全局監(jiān)視器上下文不同,該函數(shù)設置的監(jiān)視器上下文只與當前的監(jiān)視器相關聯(lián)。
buffer用于保存從 zookeeper 服務器獲取的節(jié)點數(shù)據(jù)。
buffer_lenbuffer 大小,一旦成功返回該值將會被設置為節(jié)點數(shù)據(jù)的實際大小,如果節(jié)點的數(shù)據(jù)為空,則數(shù)據(jù)大小為 -1,buffer_len 也為 -1。
stat如果非空,stat 指向的結構將會保存該節(jié)點的 Stat 信息。
  • 獲取子節(jié)點列表 get_children(四個)
ZOOAPI int zoo_get_children(zhandle_t * zh, const char *path,int watch, struct String_vector *strings);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
watch如果非0,則在服務器端設置監(jiān)視,當節(jié)點發(fā)生變化時客戶端會得到通知
strings返回各個子節(jié)點路徑

?

ZOOAPI int zoo_wget_children(zhandle_t * zh, const char *path, watcher_fn watcher, void *watcherCtx,struct String_vector *strings);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
watcher如果不為 NULL 則會在服務器端設置監(jiān)視,當節(jié)點發(fā)生變化時客戶端會得到通知
watcherCtx用戶指定的數(shù)據(jù),將被傳入到監(jiān)視器回調函數(shù)中,與由 zookeeper_init() 設置的全局監(jiān)視器上下文不同,該函數(shù)設置的監(jiān)視器上下文只與當前的監(jiān)視器相關聯(lián)。
strings回各個子節(jié)點路徑

?

ZOOAPI int zoo_get_children2(zhandle_t * zh, const char *path, int watch, struct String_vector *strings,struct Stat *stat);

該函數(shù)最早出現(xiàn)在 Zookeeper 3.3.0中,該函數(shù)功能與 zoo_get_children() 基本一致,但同時還會返回指定節(jié)點的 Stat 信息。

zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
watch如果非0,則在服務器端設置監(jiān)視,當節(jié)點發(fā)生變化時客戶端會得到通知
strings返回各個子節(jié)點路徑。
stat返回指定節(jié)點的 Stat 信息。

?

ZOOAPI int zoo_wget_children2(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,struct String_vector *strings,struct Stat *stat);

該函數(shù)最早出現(xiàn)在 Zookeeper 3.3.0中,該函數(shù)功能與 zoo_wget_children() 基本一致,但同時還會返回指定節(jié)點的 Stat 信息。

zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
watcher如果不為 NULL 則會在服務器端設置監(jiān)視,當節(jié)點發(fā)生變化時客戶端會得到通知
watcherCtx用戶指定的數(shù)據(jù),將被傳入到監(jiān)視器回調函數(shù)中,與由 zookeeper_init() 設置的全局監(jiān)視器上下文不同,該函數(shù)設置的監(jiān)視器上下文只與當前的監(jiān)視器相關聯(lián)。
strings返回各個子節(jié)點路徑。
stat返回指定節(jié)點的 Stat 信息。
  • 訪問、設置節(jié)點 ACL (兩個)
ZOOAPI int zoo_get_acl(zhandle_t * zh, const char *path, struct ACL_vector *acl, struct Stat *stat);ZOOAPI int zoo_set_acl(zhandle_t * zh, const char *path, int version, const struct ACL_vector *acl);
  • 獲取節(jié)點 ACL 信息
ZOOAPI int zoo_get_acl(zhandle_t * zh, const char *path, struct ACL_vector *acl, struct Stat *stat);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
acl該函數(shù)所返回的指定節(jié)點的 ACL 信息。
stat返回指定節(jié)點的 Stat 信息。
  • 設置節(jié)點 ACL
ZOOAPI int zoo_set_acl(zhandle_t * zh, const char *path, int version, const struct ACL_vector *acl);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
version節(jié)點的版本號。
acl需要設置的 ACL 信息。
  • 批處理,即原子性地一次提交多個 Zookeeper 操作。
ZOOAPI int zoo_multi(zhandle_t * zh, int count, const zoo_op_t * ops, zoo_op_result_t * results);
zhzookeeper_init() 返回的 zookeeper 句柄。
count提交操作的個數(shù)。
ops包含所提交操作數(shù)組。
results包含操作所返回結果的數(shù)組。

其中 zoo_op_t 是各種操作(創(chuàng)建、刪除節(jié)點,設置節(jié)點數(shù)據(jù)和檢查節(jié)點狀態(tài)四種操作)一個封裝(聯(lián)合體),定義如下:

typedef struct zoo_op {int type;union {// CREATEstruct {const char *path;const char *data;int datalen;char *buf;int buflen;const struct ACL_vector *acl;int flags;} create_op;// DELETE struct {const char *path;int version;} delete_op;// SETstruct {const char *path;const char *data;int datalen;int version;struct Stat *stat;} set_op;// CHECKstruct {const char *path;int version;} check_op;}; } zoo_op_t;

zoo_op_t 一般由以下四個函數(shù)初始化:

void zoo_create_op_init(zoo_op_t * op, const char *path, const char *value,int valuelen, const struct ACL_vector *acl,int flags, char *path_buffer, int path_buffer_len);void zoo_delete_op_init(zoo_op_t * op, const char *path, int version);void zoo_set_op_init(zoo_op_t * op, const char *path,const char *buffer, int buflen, int version,struct Stat *stat);void zoo_check_op_init(zoo_op_t * op, const char *path, int version);

zoo_op_result_t 用于保存 zoo_multi 或者 zoo_amulti 返回的其中一個結果,定義如下:

typedef struct zoo_op_result {int err;char *value;int valuelen;struct Stat *stat; } zoo_op_result_t;

?

以上內容是 Zookeeper? C API 中同步 API 的介紹,如有錯誤請留下您的想法和意見,本人會盡快更正;同時,我也將在后面的文章中列舉一些示例來說明上述 API 的用法,如有興趣請繼續(xù)關注,如果您需要了解 Zookeeper 異步 API,請移步第六講《Zookeeper C API 指南六(異步 API 介紹)》。

上一講《Zookeeper C API 指南五(同步 API 介紹)》講了Zookeeper 同步 API 的分類和相關解釋,相信大家對 Zookeeper 同步 API 也有了一個大致的了解,本文我會給大家介紹 Zookeeper C API 中的異步調用的函數(shù)(即以 zoo_a* 開頭的函數(shù)),本文大致結構與《Zookeeper C API 指南五(同步 API 介紹)》,先匯總 API,然后再分類,并對每個 API 作出解釋。

在具體講解 Zookeeper 異步 API 之前,首先回顧一下《Zookeeper C API 指南三(回調函數(shù))》,除了監(jiān)視器回調函數(shù)以外,還有其他 7 種回調函數(shù),他們通常在異步 API 調用結束或 Zookeeper? 客戶端失去連接時被調用。根據(jù)回調函數(shù)返回參數(shù)(即函數(shù)的輸出參數(shù))的類型不同分為以下幾類:返回 void 類型的回調函數(shù),返回 Stat 結構的回調函數(shù),返回字符串的回調函數(shù),返回數(shù)據(jù)的回調函數(shù),返回字符串列表(a list of string)的回調函數(shù),同時返回字符串列表(a list of string)和 Stat 結構的回調函數(shù),以及返回 ACL 信息的回調函數(shù),7 中回調函數(shù)原型聲明如下:

// 返回 void 類型的回調函數(shù) typedef void(* void_completion_t)(int rc, const void *data);// 返回 Stat 結構的回調函數(shù) typedef void(* stat_completion_t)(int rc, const struct Stat *stat, const void *data); // 返回字符串的回調函數(shù) typedef void(* string_completion_t)(int rc, const char *value, const void *data); // 返回數(shù)據(jù)的回調函數(shù) typedef void(* data_completion_t)(int rc, const char *value, int value_len, const struct Stat *stat, const void *data); // 返回字符串列表(a list of string)的回調函數(shù) typedef void(* strings_completion_t)(int rc, const struct String_vector *strings, const void *data); // 同時返回字符串列表(a list of string)和 Stat 結構的回調函數(shù) typedef void(* strings_stat_completion_t)(int rc, const struct String_vector *strings, const struct Stat *stat, const void *data); // 以及返回 ACL 信息的回調函數(shù) typedef void(* acl_completion_t)(int rc, struct ACL_vector *acl, struct Stat *stat, const void *data);

?可能這么說還不是很理解,那么我們以異步創(chuàng)建 znode 節(jié)點(zoo_acreate())為例解釋一下:

zoo_acreate函數(shù)原型如下:

ZOOAPI int zoo_acreate(zhandle_t * zh, const char *path,const char *value, int valuelen,const struct ACL_vector *acl, int flags,string_completion_t completion, const void *data);

其中參數(shù) string_completion_t completion 即返回字符串的回調函數(shù),那么當 zoo_acreate 調用結束時將會觸發(fā) completion 回調函數(shù)的調用,同時傳遞給 completion 的rc 參數(shù)為: ZOK 操作完成;ZNONODE 父節(jié)點不存在;ZNODEEXISTS 節(jié)點已存在;ZNOAUTH 客戶端沒有權限創(chuàng)建節(jié)點。ZNOCHILDRENFOREPHEMERALS 臨時節(jié)點不能創(chuàng)建子節(jié)點。而string_completion_t completion 中 const char *value 參數(shù)即新節(jié)點的路徑名(注:如果 zoo_acreate 設置了ZOO_EPHEMERAL,則創(chuàng)建節(jié)點成功后,節(jié)點名稱并不是 zoo_acreate 中 path 參數(shù)所指定的名稱,而是類似與 /xyz0000000001,/xyz0000000002... 的名稱)。另外,string_completion_t completion const void *data 參數(shù)即為 zoo_acreate 中的 const void *data。

一般來說,zoo_acreate 函數(shù)可以按照以下方式調用:

int ret = zoo_acreate(zkhandle, "/xyz", "hello", 5,&ZOO_OPEN_ACL_UNSAFE, 0 /* ZOO_SEQUENCE */,zktest_string_completion, "acreate");if (ret) {fprintf(stderr, "Error %d for %s\n", ret, "acreate");exit(EXIT_FAILURE);}

?其中 zktest_string_completion 功能很簡單,就是把創(chuàng)建成功后的節(jié)點名稱打印出來,函數(shù)定義如下:

void zktest_string_completion(int rc, const char *name, const void *data) {fprintf(stderr, "[%s]: rc = %d\n", (char*)(data==0?"null":data), rc);if (!rc) {fprintf(stderr, "\tname = %s\n", name);} }

?好了,有了上面的基礎,我們接下來再來講講 Zookeeper 異步 API 吧 :-)

Zookeeper C API 中與訪問 Zookeeper 服務相關(比如創(chuàng)建、刪除 znode 節(jié)點,獲取子節(jié)點,設置 znode 數(shù)據(jù)等)的異步 API 如下:

ZOOAPI int zoo_acreate(zhandle_t * zh, const char *path,const char *value, int valuelen,const struct ACL_vector *acl, int flags,string_completion_t completion, const void *data);ZOOAPI int zoo_adelete(zhandle_t * zh, const char *path, int version,void_completion_t completion, const void *data);ZOOAPI int zoo_aexists(zhandle_t * zh, const char *path, int watch,stat_completion_t completion, const void *data);ZOOAPI int zoo_awexists(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,stat_completion_t completion, const void *data);ZOOAPI int zoo_aget(zhandle_t * zh, const char *path, int watch,data_completion_t completion, const void *data);ZOOAPI int zoo_awget(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,data_completion_t completion, const void *data);ZOOAPI int zoo_aset(zhandle_t * zh, const char *path,const char *buffer, int buflen, int version,stat_completion_t completion, const void *data);ZOOAPI int zoo_aget_children(zhandle_t * zh, const char *path,int watch,strings_completion_t completion,const void *data);ZOOAPI int zoo_awget_children(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,strings_completion_t completion,const void *data);ZOOAPI int zoo_aget_children2(zhandle_t * zh, const char *path,int watch,strings_stat_completion_t completion,const void *data);ZOOAPI int zoo_awget_children2(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,strings_stat_completion_t completion,const void *data);ZOOAPI int zoo_async(zhandle_t * zh, const char *path,string_completion_t completion, const void *data);ZOOAPI int zoo_aget_acl(zhandle_t * zh, const char *path,acl_completion_t completion, const void *data);ZOOAPI int zoo_aset_acl(zhandle_t * zh, const char *path, int version,struct ACL_vector *acl, void_completion_t,const void *data);ZOOAPI int zoo_amulti(zhandle_t * zh, int count, const zoo_op_t * ops,zoo_op_result_t * results, void_completion_t,const void *data);

本文將以上異步 API 細分為以下幾類:(1). 創(chuàng)建、刪除 znode 節(jié)點,(2). 可設置 watch 的 API,(3). 訪問、設置節(jié)點 ACL 的 API,(4). 異步批處理 API。

  • ?創(chuàng)建、刪除 znode 節(jié)點
ZOOAPI int zoo_acreate(zhandle_t * zh, const char *path,const char *value, int valuelen,const struct ACL_vector *acl, int flags,string_completion_t completion, const void *data);ZOOAPI int zoo_adelete(zhandle_t * zh, const char *path, int version,void_completion_t completion, const void *data);
  • 創(chuàng)建 znode 節(jié)點
ZOOAPI int zoo_acreate(zhandle_t * zh, const char *path,const char *value, int valuelen,const struct ACL_vector *acl, int flags,string_completion_t completion, const void *data);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
value該節(jié)點保存的數(shù)據(jù)。
valuelen該節(jié)點保存數(shù)據(jù)的大小。
acl該節(jié)點初始 ACL,ACL 不能為null 或空。
flags該參數(shù)可以設置為 0,或者創(chuàng)建標識符 ZOO_EPHEMERAL,?ZOO_SEQUENCE 的組合或(OR)。
completion當創(chuàng)建節(jié)點請求完成時會調用該函數(shù),該函數(shù)原型詳見第三講《回調函數(shù)》一節(jié)。同時傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 父節(jié)點不存在;ZNODEEXISTS 節(jié)點已存在;ZNOAUTH 客戶端沒有權限創(chuàng)建節(jié)點。ZNOCHILDRENFOREPHEMERALS 臨時節(jié)點不能創(chuàng)建子節(jié)點。
datacompletion 函數(shù)被調用時,傳遞給 completion 的數(shù)據(jù)。
  • 刪除 znode 節(jié)點
ZOOAPI int zoo_adelete(zhandle_t * zh, const char *path, int version,void_completion_t completion, const void *data);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
version期望的節(jié)點版本號,如果真實的版本號與期望的版本號不同則 zoo_delete() 調用失敗,-1 表示不不檢查版本號。
completion當刪除節(jié)點請求完成時會調用該函數(shù),該函數(shù)原型詳見第三講《回調函數(shù)》一節(jié)。同時傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點不存在;ZNOAUTH 客戶端沒有權限刪除節(jié)點;ZBADVERSION 版包號不匹配;ZNOTEMPTY 當前節(jié)點存在子節(jié)點,不能被刪除。
datacompletion 函數(shù)被調用時,傳遞給 completion 的數(shù)據(jù)。

?

  • 可設置 watch 的 API(exists(兩個) + get(兩個) + get_children(四個) = 八個)
ZOOAPI int zoo_aexists(zhandle_t * zh, const char *path, int watch,stat_completion_t completion, const void *data);ZOOAPI int zoo_awexists(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,stat_completion_t completion, const void *data);ZOOAPI int zoo_aget(zhandle_t * zh, const char *path, int watch,data_completion_t completion, const void *data);ZOOAPI int zoo_awget(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,data_completion_t completion, const void *data);ZOOAPI int zoo_aget_children(zhandle_t * zh, const char *path,int watch,strings_completion_t completion,const void *data);ZOOAPI int zoo_awget_children(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,strings_completion_t completion,const void *data);ZOOAPI int zoo_aget_children2(zhandle_t * zh, const char *path,int watch,strings_stat_completion_t completion,const void *data);ZOOAPI int zoo_awget_children2(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,strings_stat_completion_t completion,const void *data);
  • 檢查節(jié)點狀態(tài) exists(兩個,分別是 zoo_aexists() 和 zoo_awexists(),區(qū)別是后者可以指定單獨的 watcher_fn(監(jiān)視器回調函數(shù)),而前者只能用 zookeeper_init() 設置的全局監(jiān)視器回調函數(shù),同時 aget 和 aget_children兩族函數(shù)也一樣,帶有zoo_w* 的函數(shù)可以指定單獨的 watcher_fn)。)
ZOOAPI int zoo_aexists(zhandle_t * zh, const char *path, int watch,stat_completion_t completion, const void *data);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
watch如果非 0,則在服務器端設置監(jiān)視,當節(jié)點發(fā)生變化時客戶端會得到通知,即使當前指定的節(jié)點不存在也會設置監(jiān)視,這樣該節(jié)點被創(chuàng)建時,客戶端也可以得到通知。
completion當 zoo_aexists 請求完成時會調用該函數(shù),該函數(shù)原型詳見第三講《回調函數(shù)》一節(jié)。同時傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點不存在;ZNOAUTH 客戶端沒有權限刪除節(jié)點。
datacompletion 函數(shù)被調用時,傳遞給 completion 的數(shù)據(jù)。

?

ZOOAPI int zoo_awexists(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,stat_completion_t completion, const void *data);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
watcher如果非 0,則在服務器端設置監(jiān)視,當節(jié)點發(fā)生變化時客戶端會得到通知,即使當前指定的節(jié)點不存在也會設置監(jiān)視,這樣該節(jié)點被創(chuàng)建時,客戶端也可以得到通知。
watcherCtx用戶指定的數(shù)據(jù),將被傳入到監(jiān)視器回調函數(shù)中,與由 zookeeper_init() 設置的全局監(jiān)視器上下文不同,該函數(shù)設置的監(jiān)視器上下文只與當前的監(jiān)視器相關聯(lián)。
completionzoo_awexists 請求完成時會調用該函數(shù),該函數(shù)原型詳見第三講《回調函數(shù)》一節(jié)。同時傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點不存在;ZNOAUTH 客戶端沒有權限刪除節(jié)點。
datacompletion 函數(shù)被調用時,傳遞給 completion 的數(shù)據(jù)。

?

  • 獲取節(jié)點數(shù)據(jù) aget(兩個)
ZOOAPI int zoo_aget(zhandle_t * zh, const char *path, int watch,data_completion_t completion, const void *data);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
watch如果非 0,則在服務器端設置監(jiān)視,當節(jié)點發(fā)生變化時客戶端會得到通知。
completionzoo_aget 請求完成時會調用該函數(shù),該函數(shù)原型詳見第三講《回調函數(shù)》一節(jié)。同時傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點不存在;ZNOAUTH 客戶端沒有權限刪除節(jié)點。
datacompletion 函數(shù)被調用時,傳遞給 completion 的數(shù)據(jù)。

?

ZOOAPI int zoo_awget(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,data_completion_t completion, const void *data);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
watcher如果非 0,則在服務器端設置監(jiān)視,當節(jié)點發(fā)生變化時客戶端會得到通知,即使當前指定的節(jié)點不存在也會設置監(jiān)視,這樣該節(jié)點被創(chuàng)建時,客戶端也可以得到通知。
watcherCtx用戶指定的數(shù)據(jù),將被傳入到監(jiān)視器回調函數(shù)中,與由 zookeeper_init() 設置的全局監(jiān)視器上下文不同,該函數(shù)設置的監(jiān)視器上下文只與當前的監(jiān)視器相關聯(lián)。
completionzoo_awget 請求完成時會調用該函數(shù),該函數(shù)原型詳見第三講《回調函數(shù)》一節(jié)。同時傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點不存在;ZNOAUTH 客戶端沒有權限刪除節(jié)點。
datacompletion 函數(shù)被調用時,傳遞給 completion 的數(shù)據(jù)。

?

  • 獲取子節(jié)點列表 aget_children (四個)
ZOOAPI int zoo_aget_children(zhandle_t * zh, const char *path,int watch,strings_completion_t completion,const void *data);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
watch如果非 0,則在服務器端設置監(jiān)視,當節(jié)點發(fā)生變化時客戶端會得到通知。
completion當 zoo_aget_children 請求完成時會調用該函數(shù),該函數(shù)原型詳見第三講《回調函數(shù)》一節(jié)。同時傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點不存在;ZNOAUTH 客戶端沒有權限刪除節(jié)點。
datacompletion 函數(shù)被調用時,傳遞給 completion 的數(shù)據(jù)。

?

ZOOAPI int zoo_awget_children(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,strings_completion_t completion,const void *data);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
watcher如果非 0,則在服務器端設置監(jiān)視,當節(jié)點發(fā)生變化時客戶端會得到通知,即使當前指定的節(jié)點不存在也會設置監(jiān)視,這樣該節(jié)點被創(chuàng)建時,客戶端也可以得到通知。
watcherCtx用戶指定的數(shù)據(jù),將被傳入到監(jiān)視器回調函數(shù)中,與由 zookeeper_init() 設置的全局監(jiān)視器上下文不同,該函數(shù)設置的監(jiān)視器上下文只與當前的監(jiān)視器相關聯(lián)。
completion當zoo_awget_children 請求完成時會調用該函數(shù),該函數(shù)原型詳見第三講《回調函數(shù)》一節(jié)。同時傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點不存在;ZNOAUTH 客戶端沒有權限刪除節(jié)點。
datacompletion 函數(shù)被調用時,傳遞給 completion 的數(shù)據(jù)。

?

ZOOAPI int zoo_aget_children2(zhandle_t * zh, const char *path,int watch,strings_stat_completion_t completion,const void *data);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
watch如果非 0,則在服務器端設置監(jiān)視,當節(jié)點發(fā)生變化時客戶端會得到通知。
completion當 zoo_aget_children2 請求完成時會調用該函數(shù),該函數(shù)原型詳見第三講《回調函數(shù)》一節(jié)。同時傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點不存在;ZNOAUTH 客戶端沒有權限刪除節(jié)點。
datacompletion 函數(shù)被調用時,傳遞給 completion 的數(shù)據(jù)。

?

ZOOAPI int zoo_awget_children2(zhandle_t * zh, const char *path,watcher_fn watcher, void *watcherCtx,strings_stat_completion_t completion,const void *data);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
watcher如果非 0,則在服務器端設置監(jiān)視,當節(jié)點發(fā)生變化時客戶端會得到通知,即使當前指定的節(jié)點不存在也會設置監(jiān)視,這樣該節(jié)點被創(chuàng)建時,客戶端也可以得到通知。
watcherCtx用戶指定的數(shù)據(jù),將被傳入到監(jiān)視器回調函數(shù)中,與由 zookeeper_init() 設置的全局監(jiān)視器上下文不同,該函數(shù)設置的監(jiān)視器上下文只與當前的監(jiān)視器相關聯(lián)。
completion當zoo_awget_children2 請求完成時會調用該函數(shù),該函數(shù)原型詳見第三講《回調函數(shù)》一節(jié)。同時傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點不存在;ZNOAUTH 客戶端沒有權限刪除節(jié)點。
datacompletion 函數(shù)被調用時,傳遞給 completion 的數(shù)據(jù)。

?

  • 訪問、設置節(jié)點 ACL 的 API
ZOOAPI int zoo_aget_acl(zhandle_t * zh, const char *path,acl_completion_t completion, const void *data);ZOOAPI int zoo_aset_acl(zhandle_t * zh, const char *path, int version,struct ACL_vector *acl, void_completion_t,const void *data);
  • 訪問節(jié)點 ACL
ZOOAPI int zoo_aget_acl(zhandle_t * zh, const char *path,acl_completion_t completion, const void *data);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
completion當 zoo_aget_acl 請求完成時會調用該函數(shù),該函數(shù)原型詳見第三講《回調函數(shù)》一節(jié)。同時傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點不存在;ZNOAUTH 客戶端沒有權限刪除節(jié)點。
datacompletion 函數(shù)被調用時,傳遞給 completion 的數(shù)據(jù)。

?

  • 設置節(jié)點 ACL
ZOOAPI int zoo_aset_acl(zhandle_t * zh, const char *path, int version,struct ACL_vector *acl, void_completion_t,const void *data);
zhzookeeper_init() 返回的 zookeeper 句柄。
path節(jié)點路徑。
buffer保存需要設置的 ACL。
buflenbuffer 的長度。
completion當 zoo_aset_acl 請求完成時會調用該函數(shù),該函數(shù)原型詳見第三講《回調函數(shù)》一節(jié)。同時傳遞給completion的rc參數(shù)為: ZOK 操作完成;ZNONODE 節(jié)點不存在;ZNOAUTH 客戶端沒有權限刪除節(jié)點;ZINVALIDACL 非法 ACL;ZBADVERSION 版本號不匹配。
datacompletion 函數(shù)被調用時,傳遞給 completion 的數(shù)據(jù)。

?

  • 異步批處理 API
ZOOAPI int zoo_amulti(zhandle_t * zh, int count, const zoo_op_t * ops,zoo_op_result_t * results, void_completion_t,const void *data);

異步批處理與同步批處理方式類似見《Zookeeper C API 指南五(同步 API 介紹)》,只是需要額外設置一個 void_completion_t 回調函數(shù),在此不再贅述。

?

以上內容是 Zookeeper? C API 中異步 API 的介紹,如有錯誤請留下您的想法和意見,我會盡快更正;同時,我也將在后面的文章中列舉一些示例來說明上述 API 的用法,如有興趣請繼續(xù)關注。

在前面的文章中我們講了大部分 Zookeeper? C API,相信大家已經(jīng)知道怎樣使用 Zookeeper? C API了吧。我曾在《Zookeeper C API 指南》系列文章的第四篇《Zookeeper C API 指南四(C API 概覽)》中也 Zookeeper C API 的分為了 5 類,他們分別是:(1)、初始化、銷毀 Zookeeper 句柄,(2)、與 zoo_multi() 和 zoo_amulti() 批量操作相關的 zoo_op_t 初始化函數(shù),(3)、同步 API,(4)、異步 API,(5)、輔助函數(shù)。其中“(1)、初始化、銷毀 Zookeeper 句柄”已經(jīng)在《Zookeeper C API 指南四(C API 概覽)》中介紹過了,并且在《Zookeeper C API 指南五(同步 API 介紹)》和《Zookeeper C API 指南六(異步 API 介紹)》中我們又分別講了“同步 API” 和 “異步 API”(其中也簡單地介紹了一下與 zoo_multi() 和 zoo_amulti() 批量操作相關的 zoo_op_t 初始化函數(shù)),所以接下來我們再來講講 Zookeeper C API 中的 “輔助函數(shù)”。

我們分類的 Zookeeper C API 中輔助函數(shù)如下:

ZOOAPI void zoo_set_debug_level(ZooLogLevel logLevel);ZOOAPI void zoo_set_log_stream(FILE * logStream);ZOOAPI const clientid_t *zoo_client_id(zhandle_t * zh);ZOOAPI int zoo_recv_timeout(zhandle_t * zh);ZOOAPI const void *zoo_get_context(zhandle_t * zh);ZOOAPI void zoo_set_context(zhandle_t * zh, void *context);ZOOAPI watcher_fn zoo_set_watcher(zhandle_t * zh, watcher_fn newFn);ZOOAPI struct sockaddr *zookeeper_get_connected_host(zhandle_t * zh, struct sockaddr*addr,socklen_t * addr_len);ZOOAPI int zookeeper_interest(zhandle_t * zh, int *fd, int *interest,struct timeval *tv);ZOOAPI int zookeeper_process(zhandle_t * zh, int events);ZOOAPI int zoo_state(zhandle_t * zh);ZOOAPI const char *zerror(int c);ZOOAPI int is_unrecoverable(zhandle_t * zh);ZOOAPI void zoo_deterministic_conn_order(int yesOrNo);

下面我們來講講其中比較常用的幾個函數(shù)吧 :-)

  • ?設置日志等級
ZOOAPI void zoo_set_debug_level(ZooLogLevel logLevel);

其中 logLevel 可以是ZOO_LOG_LEVEL_ERROR, ZOO_LOG_LEVEL_WARN,ZOO_LOG_LEVEL_INFO, ZOO_LOG_LEVEL_DEBUG四個取值。

?

  • 設置日志流
ZOOAPI void zoo_set_log_stream(FILE * logStream);

Zookeeper C API 默認的日志流是標準輸出,可以通過該函數(shù)設置 Zookeeper C API的日志流為文件。

?

  • 獲取客戶端的 session id,只有在客戶端的當前連接狀態(tài)有效時才可以。
ZOOAPI const clientid_t *zoo_client_id(zhandle_t * zh);

?

  • 返回當前會話的超時時間,只有在客戶端的當前連接狀態(tài)有效時才可以。
ZOOAPI int zoo_recv_timeout(zhandle_t * zh);

?

  • 獲取 Zookeeper 句柄的上下文。
ZOOAPI const void *zoo_get_context(zhandle_t * zh);

?

  • 設置 Zookeeper 句柄的上下文。
ZOOAPI void zoo_set_context(zhandle_t * zh, void *context);

?

  • 設置 Zookeeper 句柄的全局監(jiān)視器回調函數(shù),該函數(shù)返回全局監(jiān)視器的舊回調函數(shù)。
ZOOAPI watcher_fn zoo_set_watcher(zhandle_t * zh, watcher_fn newFn);

?

  • 返回當前 Zookeeper 連接的套接字地址。
ZOOAPI struct sockaddr *zookeeper_get_connected_host(zhandle_t * zh, struct sockaddr*addr,socklen_t * addr_len);

?

  • 獲取當前 Zookeeper 連接狀態(tài)。
ZOOAPI int zoo_state(zhandle_t * zh);

?

  • 返回某一錯誤碼的字符串表示。
ZOOAPI const char *zerror(int c);

?

  • 檢查當前 Zookeeper 連接是否為不可恢復的,如果不可恢復,則客戶端需要關閉連接,然后重連。
ZOOAPI int is_unrecoverable(zhandle_t * zh);

?

好了,Zookeeper 大部分的輔助函數(shù)就介紹到這里了,大家可以更多文檔可以在 zookeeper.h 中找到。:-)

前面七講我們基本上介紹完了 Zookeeper C API 的所有內容,本文將結合一個小例子講講如何在你的實際項目中使用 Zookeeper 服務。

設想如下場景:

假設程序 A 需要 7* 24 小時在線對外提供服務,但是 A 程序在生產(chǎn)環(huán)境下總是不穩(wěn)定,時常崩潰,不過幸運的是解決方案很簡單,在 A 程序崩潰以后只需要重啟它就可以了。當然如此簡單的問題你可以提出多種解決方案,比方說自己實現(xiàn)一個服務程序,每隔一定時間去輪詢 A 的狀態(tài),如果發(fā)現(xiàn) A 崩潰了,立即重啟它,并向管理人員報告問題。不過我們并不打算這么做,畢竟本文主題是講 Zookeeper C API 的應用,所以我們采用 Zookeeper 服務來解決該問題。

若采用 Zookeeper 服務可以按照如下方案解決問題,程序 A 在啟動時創(chuàng)建一個臨時(ZOO_EPHEMERAL) znode 節(jié)點 /A,然后按照正常流程對外提供服務。另外監(jiān)控程序對 /A 節(jié)點設置監(jiān)視,當 /A 節(jié)點消失(說明 A 程序已經(jīng)崩潰)時,重啟 A 程序。假設 A 的名稱是 QueryServer,即對外提供查詢服務的程序,具體提供什么查詢服務由應用自身決定,我們這里只是簡單地模擬一下。QueryServer 在啟動時創(chuàng)建一個 /QueryServer 的臨時節(jié)點(ZOO_EPHEMERAL),然后,程序 QueryServerd 監(jiān)控 /QueryServer 節(jié)點,當 /QueryServer 節(jié)點消失(說明 A 程序已經(jīng)崩潰)時,重啟?QueryServer 程序。

下面是 QueryServer 的實現(xiàn)代碼:

/** =============================================================================** Filename: QueryServer.c** Description: QueryServer** Created: 02/15/2013 08:48:49 PM** Author: Fu Haiping (forhappy), haipingf@gmail.com* Company: ICT ( Institute Of Computing Technology, CAS )** =============================================================================*/ #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <zookeeper/zookeeper.h> #include <zookeeper/zookeeper_log.h>void QueryServer_watcher_g(zhandle_t* zh, int type, int state,const char* path, void* watcherCtx) {if (type == ZOO_SESSION_EVENT) {if (state == ZOO_CONNECTED_STATE) {printf("[[[QueryServer]]] Connected to zookeeper service successfully!\n");} else if (state == ZOO_EXPIRED_SESSION_STATE) { printf("Zookeeper session expired!\n");}} }void QueryServer_string_completion(int rc, const char *name, const void *data) {fprintf(stderr, "[%s]: rc = %d\n", (char*)(data==0?"null":data), rc);if (!rc) {fprintf(stderr, "\tname = %s\n", name);} }void QueryServer_accept_query() {printf("QueryServer is running...\n"); }int main(int argc, const char *argv[]) {const char* host = "127.0.0.1:2181,127.0.0.1:2182,""127.0.0.1:2183,127.0.0.1:2184,127.0.0.1:2185";int timeout = 30000;zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);zhandle_t* zkhandle = zookeeper_init(host,QueryServer_watcher_g, timeout, 0, "hello zookeeper.", 0);if (zkhandle == NULL) {fprintf(stderr, "Error when connecting to zookeeper servers...\n");exit(EXIT_FAILURE);}// struct ACL ALL_ACL[] = {{ZOO_PERM_ALL, ZOO_ANYONE_ID_UNSAFE}};// struct ACL_vector ALL_PERMS = {1, ALL_ACL};int ret = zoo_acreate(zkhandle, "/QueryServer", "alive", 5,&ZOO_OPEN_ACL_UNSAFE, ZOO_EPHEMERAL,QueryServer_string_completion, "zoo_acreate");if (ret) {fprintf(stderr, "Error %d for %s\n", ret, "acreate");exit(EXIT_FAILURE);}do {// 模擬 QueryServer 對外提供服務.// 為了簡單起見, 我們在此調用一個簡單的函數(shù)來模擬 QueryServer.// 然后休眠 5 秒,程序主動退出(即假設此時已經(jīng)崩潰). QueryServer_accept_query();sleep(5);} while(false);zookeeper_close(zkhandle); }

Makefile如下:

all:QueryServerQueryServer:QueryServer.ogcc -L/usr/local/lib/ -lzookeeper_mt -o $@ $^ QueryServer.o:QueryServer.cgcc -DTHREADED -I/usr/local/include/zookeeper -o $@ -c $^.PHONY:cleanclean:rm QueryServer.o QueryServer

?

QueryServerd 代碼如下:

/** =============================================================================** Filename: QueryServerd.c** Description: QueryServer daemon using zookeeper. ** Created: 02/15/2013 08:48:49 PM** Author: Fu Haiping (forhappy), haipingf@gmail.com* Company: ICT ( Institute Of Computing Technology, CAS )** =============================================================================*/ #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <zookeeper/zookeeper.h> #include <zookeeper/zookeeper_log.h>void QueryServerd_watcher_global(zhandle_t * zh, int type, int state,const char *path, void *watcherCtx); static void QueryServerd_dump_stat(const struct Stat *stat); void QueryServerd_stat_completion(int rc, const struct Stat *stat,const void *data); void QueryServerd_watcher_awexists(zhandle_t *zh, int type, int state,const char *path, void *watcherCtx); static void QueryServerd_awexists(zhandle_t *zh);void QueryServerd_watcher_global(zhandle_t * zh, int type, int state,const char *path, void *watcherCtx) {if (type == ZOO_SESSION_EVENT) {if (state == ZOO_CONNECTED_STATE) {printf("Connected to zookeeper service successfully!\n");} else if (state == ZOO_EXPIRED_SESSION_STATE) { printf("Zookeeper session expired!\n");}} }static void QueryServerd_dump_stat(const struct Stat *stat) {char tctimes[40];char tmtimes[40];time_t tctime;time_t tmtime;if (!stat) {fprintf(stderr, "null\n");return;}tctime = stat->ctime / 1000;tmtime = stat->mtime / 1000;ctime_r(&tmtime, tmtimes);ctime_r(&tctime, tctimes);fprintf(stderr, "\tctime = %s\tczxid=%llx\n""\tmtime=%s\tmzxid=%llx\n""\tversion=%x\taversion=%x\n""\tephemeralOwner = %llx\n",tctimes, stat->czxid,tmtimes, stat->mzxid,(unsigned int) stat->version, (unsigned int) stat->aversion,stat->ephemeralOwner); }void QueryServerd_stat_completion(int rc, const struct Stat *stat,const void *data) {// fprintf(stderr, "%s: rc = %d Stat:\n", (char *) data, rc);// QueryServerd_dump_stat(stat); }void QueryServerd_watcher_awexists(zhandle_t *zh, int type, int state,const char *path, void *watcherCtx) {if (state == ZOO_CONNECTED_STATE) {if (type == ZOO_DELETED_EVENT) {printf("QueryServer gone away, restart now...\n");// re-exists and set watch on /QueryServer again. QueryServerd_awexists(zh);pid_t pid = fork();if (pid < 0) {fprintf(stderr, "Error when doing fork.\n");exit(EXIT_FAILURE);}if (pid == 0) { /* child process */// 重啟 QueryServer 服務.execl("/tmp/QueryServer/QueryServer", "QueryServer", NULL);exit(EXIT_SUCCESS);}sleep(1); /* sleep 1 second for purpose. */} else if (type == ZOO_CREATED_EVENT) {printf("QueryServer started...\n");}}// re-exists and set watch on /QueryServer again. QueryServerd_awexists(zh); }static void QueryServerd_awexists(zhandle_t *zh) {int ret =zoo_awexists(zh, "/QueryServer",QueryServerd_watcher_awexists,"QueryServerd_awexists.",QueryServerd_stat_completion,"zoo_awexists");if (ret) {fprintf(stderr, "Error %d for %s\n", ret, "aexists");exit(EXIT_FAILURE);} }int main(int argc, const char *argv[]) {const char *host = "127.0.0.1:2181,127.0.0.1:2182,""127.0.0.1:2183,127.0.0.1:2184,127.0.0.1:2185";int timeout = 30000;zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);zhandle_t *zkhandle = zookeeper_init(host,QueryServerd_watcher_global,timeout,0, "QueryServerd", 0);if (zkhandle == NULL) {fprintf(stderr, "Error when connecting to zookeeper servers...\n");exit(EXIT_FAILURE);}QueryServerd_awexists(zkhandle);// Wait for asynchronous zookeeper call done. getchar();zookeeper_close(zkhandle);return 0; }

?

Makefile 如下:

all:QueryServerdQueryServerd:QueryServerd.ogcc -L/usr/local/lib/ -lzookeeper_mt -o $@ $^ QueryServerd.o:QueryServerd.cgcc -g -DTHREADED -I/usr/local/include/zookeeper -o $@ -c $^.PHONY:cleanclean:rm QueryServerd.o QueryServerd

?

首先執(zhí)行 QueryServerd,

forhappy@haiping-ict:/tmp/QueryServerd$ ./QueryServerd Connected to zookeeper service successfully!

然后執(zhí)行 QueryServer,

forhappy@haiping-ict:/tmp/QueryServer$ ./QueryServer QueryServer is running... [[[QueryServer]]] Connected to zookeeper service successfully! [zoo_acreate]: rc = 0name = /QueryServer

可見 Queryerver 創(chuàng)建了 /QueryServer 節(jié)點,5 秒后 QueryServer 模擬程序崩潰而退出,那么此時在 QueryServerd 端輸出如下:

Connected to zookeeper service successfully! QueryServer started... # QueryServerd 感知到 QueryServer 已正常啟動. QueryServer gone away, restart now... # 5 秒鐘后,QueryServer 崩潰,QueryServerd 準備重啟 QueryServer. QueryServer is running... #?QueryServer 正在運行,以下 3 行是 QueryServer 輸出結果。 [[[QueryServer]]] Connected to zookeeper service successfully! [zoo_acreate]: rc = 0name = /QueryServer QueryServer started... #?QueryServerd 感知到 QueryServer 已正常啟動. QueryServer gone away, restart now...# 又過了 5 秒鐘后,QueryServer 崩潰,QueryServerd 準備重啟 QueryServer. QueryServer is running... #?QueryServer 再次運行,以下 3 行是 QueryServer 輸出結果。 [[[QueryServer]]] Connected to zookeeper service successfully! [zoo_acreate]: rc = 0name = /QueryServer QueryServer started... #?QueryServerd 再次感知到 QueryServer 已正常啟動,如此反復. QueryServer gone away, restart now... QueryServer is running... [[[QueryServer]]] Connected to zookeeper service successfully! [zoo_acreate]: rc = 0name = /QueryServer QueryServer started...

即 QueryServer 每 5 秒鐘崩潰一次,然后又被 QueryServerd 重啟,模擬了上面的應用場景。

好了 Zookeeper C API 的應用小示例講完了,可能應用場景選取的不好,不過大致可以一些說明問題吧,如果你想看 Zookeeper 更貼近現(xiàn)實的應用場景,可以參考淘寶的一篇文章《ZooKeeper典型應用場景一覽》和 IBM developerWorks 的一篇博文《分布式服務框架 Zookeeper -- 管理分布式環(huán)境中的數(shù)據(jù)》。


總結

以上是生活随笔為你收集整理的Zookeeper C API 指南的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。