天天看點

webtail——檔案監控

檔案監控直接通過了linux的inotify接口實作。這裡沒有考慮移植性,也就沒像tailf那樣,通過宏來判斷是否支援inotify,如果不支援,降級使用循環輪尋的方式讀取。

inotify的使用還是比較友善的基本上就是:inotify_init,inotify_add_watch,然後配合read系統調用,擷取檔案修改資訊。是以實作也非常友善。

首先是在構造函數裡面初始化inotify:

[cce lang=”cpp”]

inotifyfd = inotify_init();

[/cce]

然後提供一個watch接口,通過傳入前文描述的tfile對象和内容讀取的回調函數,添加對應檔案的監控和回調。

void filewatcher::watch ( boost::shared_ptr< tfile > tfile, std::list< filewatcher::readcallback > callbacklist )

{

if(!tfile->haserror() && !callbacklist.empty()) {

int wd = inotify_add_watch(inotifyfd, tfile->name().c_str(), in_modify);

if(wd > 0) {

tfilemap.insert(std::make_pair<int, boost::shared_ptr<tfile> >(wd, tfile));

callbackmap.insert(std::make_pair<int, std::list<readcallback> >(wd, callbacklist));

//init read

std::string initcontent = tfile->read();

boost_foreach(readcallback &callback, callbacklist) {

callback(initcontent);

}

這裡通過tfile的檔案名,向核心注冊添加該檔案的modify事件,并且在注冊成功之後,進行初始讀取(這裡有個小問題,由于後面websocket端沒有做緩存,是以由于初始讀取的時候還沒有任何websocket用戶端連接配接,是以通過web無法讀取初始内容,也就是檔案最後10行)。同時,這個類維護兩個hashmap,分别是監聽描述符wd->tfile和wd->callbacklist。

監聽完成後,就是啟動監聽,也就是通過讀取fd,感覺被監聽檔案的變更,由于這裡隻監聽了檔案修改,那麼讀取到這個事件之後,就可以對該檔案進行增量讀取(前文已經描述了讀取方法)。

char * buffer = new char[inotifybuffersize];

while(!_interrupted) {

if(read(inotifyfd, buffer, inotifybuffersize) < 0) {

if(errno == eintr) {

// interrupt

delete buffer;

return;

struct inotify_event *event = ( struct inotify_event * ) buffer;

int wd = event->wd;

boost_auto(tfileiter, tfilemap.find(wd));

if(tfileiter != tfilemap.end()) {

boost::shared_ptr<tfile> tfile = tfileiter->second;

std::string content = tfile->read();

boost_auto(iter, callbackmap.find(wd));

if(iter != callbackmap.end()) {

std::list<readcallback> callbacks = iter->second;

boost_foreach(readcallback &callback, callbacks) {

callback(content);

這裡參照inotify的文檔,首先讀取緩沖區大小設定為

static const int inotifybuffersize = sizeof(struct inotify_event) + name_max + 1;

也就是inotify_event結構的長度,和名字最大值。由于inotify_event是變長字段(包含一個可選的檔案名字段),是以這裡采用了系統限制的檔案名最大值name_max,這個宏在climits中定義,在linux中大小為255位元組。

然後通過系統調用read,讀取檔案描述符inotifyfd,這裡如果沒有新的事件産生,read會進入阻塞狀态,節省系統資源。如果有傳回,則處理傳回的inotify_event對象(注意在監聽modify事件的時候,是沒有檔案名的)。通過結構中的wd,從之前儲存的hashmap中擷取對應的tfile對象進行增量讀取,然後再讀取wd對應的回調函數,将讀取内容傳回。

這裡有個小問題需要處理,就是如何中斷讀取。之前為了在gtest中能夠通過單元測試的方式進行測試,通過檢視手冊可以知道,如果read調用被系統信号中斷,會标記錯誤碼為eintr。是以,當讀取失敗的時候,可以通過對errno檢查,判斷是否是信号中斷。

由于程式會一直運作,知道通過信号終止,是以析構變的不是很重要了。這裡析構函數裡面通過調用inotify_rm_watch将之前儲存的wd全部去掉,然後通過close調用交inotify的檔案描述符關閉即可:

filewatcher::~filewatcher()

if(inotifyfd > 0) {

boost::unordered::unordered_map<int, boost::shared_ptr<tfile> >::iterator iter;

for(iter = tfilemap.begin(); iter != tfilemap.end(); ++iter) {

inotify_rm_watch(inotifyfd, iter->first);

close(inotifyfd);

轉載自:https://coolex.info/blog/406.html

繼續閱讀