in Uncategorized

FAM_API_中文手册

/*************************************************/
/*本文档由鸿剑青翻译,原始英文文档在             */
/*http://techpubs.sgi.com/library/tpl/c*/
/*i-bin/getdoc.cgi/0650/bks/SGI_Develop*/
/*er/books/IIDsktp_IG/sgi_html/ch08.htm*/
/*l#LE29093-PARENT                     */
/*日期:2005年8月31日                            */
/*双横线中的内容未代码 */
/*单横线中的内容为提示或注意事项 */
/*自己翻译的,如有问题请指正,谢谢! */
/*************************************************/

FAM接口

这一节描述了你的应用程序连接到FAM所使用的函数。

1打开和关闭一个FAM连接
函数FAMOpen()打开一个到fam的连接。
=======================================
int FAMOpen(FAMConnection* fc)
=======================================
如果成功,FAMOpen()返回0,如果失败,则返回-1。FAMOpen()初始化的FAMConnection结构体将被用于传递给所有在你应用程序中被调用的FAM子进程。

FAMConnection结构体中有一个基本的元素,它是FAM用来和你的应用程序进行通信的接口(socket)的相关文件描述符。你需要这个文件描述符在socket上执行select()操作。你可以通过使用FAMCONNECTION_GETFD()宏来获得这个文件描述符。
=======================================
FAMCONNECTION_GETFD(fc)
=======================================
函数FAMOpen2告诉FAM应用程序的名字
=======================================
int FAMOpen2(FAMConnection* fc, const char* appName)
=======================================
当FAM打印出错信息的时候会使用到应用程序名(appName)

函数FAMClose()关闭一个到fam的连接
=======================================
int FAMClose(FAMConnection* fc)
=======================================
如果成功,FAMClose()返回0,否则返回-1.

2监视一个文件或目录

FAMMonitorDirecotry()和FAMMonitorFile()分别告诉FAM开始的监视一个目录和文件。
=======================================
int FAMMonitorDirecotry(FAMConnection *fc,char *filename,FAMRequest* fr,void* userData)

int FAMMonitorFile(FAMConnection *fc,char *filename,FAMRequest* fr,void* userData)
======================================
FAMMonitorDirectory()不仅仅监视指定的目录文件本身的变化,还监视该目录下文件的变化。如果该目录包含有子目录,则FAMMonitorDirecotry()仅仅只监视这些子目录的变化,而不监视这些子目录下文件和目录的变化。FAMMonitorFile()仅仅只显示指定文件发生了什么变化。这两个函数在成功后都返回0,否则都返回-1.

这些函数的第一个参数是被FAMOpen()初始化的FAMConnection结构体。第二个参数是要被监视的目录或文件的全路径及名称。注意,不能使用相对路径。

第三个参数是这两个函数初始化的一个FAMRequest结构体。你可以传递这个结构体给FAMSuspendMonitor(),FAMResumeMonitor()或FAMCancelMonitor()去分别暂停、恢复或取消对文件或目录的监视。

第四个参数是一个指针,这个指针指向了当一个文件或目录改变时,你所想要包含进由FAMNextEvent()返回的FAMEvent结构体中的一个强制(arbitrary)用户数据。

不论何时,当FAM侦测到所监视的文件或目录改变时,FAM产生FAM事件。

两个相似的例程是FAMMonitorDirectory2()和FAMMonitorFile2():
===============================================
int FAMMonitorDirectory2(FAMConnection *fc,char *filename,FAMrequest* fr);

int FAMMonitorFiles2(FAMConnection *fc,char *filename,FAMRequet* fr);
===============================================
在这两个例程中,调用者挑选请求号码,而不是libfam,调用者在调用之前通过把要求的号码放置在FAMRequest中来指定所要求的号码。比如:
===============================================
FAMConnection fc;
FAMRequest frq;

frq.reqnum=some_number_associated_with_tmp;
if (FAMMonitorDirectory2(&fc,"/tmp",&frq) <0)
        perror("can’t monitor /tmp");
===============================================
如果你使用-2例程,你必须选择独一无二的要求号码,参看下面的FAMAcknowledge.

使用哪种例程是由你自己决定的:-2例程或原始例程。

3暂停、恢复和取消监视
一旦你已经开始监视一个文件或目录,那么你可以取消或临时暂停监视,以及以后再恢复监视。

FAMSuspendMonitor()临时暂停监视一个文件或目录。FAMResumeMonitor()恢复对一个文件或目录的监视。当你的应用程序不需要显示关于某个文件的信息是,暂停监视是非常有用的。
———————————————–
注意:FAM在暂停监视的时候会将文件所发生的任何改变排成队列,当你的应用程序恢复监视的时候,文件所有的改变
都会被通知。
———————————————–
这些函数的语法如下:
===============================================
int FAMSuspendMonitor(FAMConnection *fc,FAMRequest *fr);

int FAMResumeMonitor(FAMConnection *fc,FAMRequest *fr);
===============================================
fc是由FAMOpen()所返回的FAMConnection,fr是由FAMMonitorFile()或FAMMonitorDirecotry()所返回的FAMRequest。两个函数在成功后都返回0,否则返回-1.

当你的应用程序完成对一个文件或目录的监视后,它应该呼叫FAMCancelMonitor():
===============================================
int FAMCancelMonitor(FAMConnection *fc,FAMRequest *fr)
===============================================
FAMCancelMonitor()命令FAM不再对由fr所指定的文件或目录进行监视。如果成功返回0,否则返回-1.

调用完FAMCancelMonitor(),FAM发送一个FAMAcknowledge事件,当你已经看过FAMAcknowledge事件,你会知道它安全的重新使用了请求号码(如果你在使用-2形式的例程)

4侦测文件和目录的改变

无论何时FAM侦测到它所监视的文件发生改变,都会产生一个FAM事件,你的应用程序可以通过两种方法中的一种来接收FAM事件:
Select方法
        你的应用程序执行一个select(2)在一个文件描述符上,这个文件描述符存在于FAMOpen()返回的FAMConnection结构体中。当这个文件描述符变成激活的,应用程序调用FAMNextEvent()去检索(取回retrieve)即将到来(pending)的FAM事件。
Polling方法
        你的应用程序周期性的调用FAMPending()(通常为系统等待输入)。当FAMPending返回一个正数的值时,你的应用程序呼叫FAMNextEvent()去检索(取回retrieve)随后的(pending)FAM事件。
FAMPending()有着如下的语法:
==============================================
int FAMPending(FAMConnection *fc)
==============================================
如果存在一个FAM事件队列,则它返回1,如果没有FAM事件队列则返回0,如果发生错误则返回-1。FAMPending()不会等待一个事件,它即时返回值。

一旦你确定存在一个FAM事件队列,不论使用select方法还是polling方法,都调用FAMNextEvent()去接收(retrieve)它。
==============================================
int FAMNextEvent(FAMConnection *fc,FAMEvent *fe)
==============================================
如果成功,FAMNextEvent()返回0,如果存在一个错误则返回-1.FAMNextEvent()的第一个参数是由FAMOpen()初始化的FAMConnection结构体。第二个参数是一个指向FAMEvent结构体的指针,这个结构体由FAMNextEvent()用关于FAM事件的信息填充。FAMEvent结构体的格式是:
==============================================
typedf struct{
        FAMConnection* fc;
        FAMRequest fr;
        char *hostname;
        char filename[PATH_MAX];
        void *userdata;
        FAMCodes code;
        }FAMEvent;
==============================================
fc是由FAMOpen()初始化的FAMConnection结构体。

fr是当你所要求被FAM监视的文件或目录发生改变后,由FAMMonitorFile()或FAMMonitorDirecotry()所返回的FAMRequest结构体。

hostname是一个废旧的字段。不要在你的应用程序里使用它。

filename是被你所监视的文件或目录的完整的路径和文件名。

userdata是当你调用FAMMonitorFile()或FAMMonitorDirectory()时,由你提供的一个强制数据的指针。如果你使用-2例程FAMMonitorDirector2()或FAMMonitorFile2(),userdata是没有定义的。

code是用于描述发生改变的FAMCodes的枚举类型的值,它可以采用以下的任意值:
FAMChanged      关于文件或目录可以获得的最后改变的一些值
FAMDeleted      被监视的文件或目录被删除了。
FAMStartExecuting 一个被监视的可执行文件被执行了,这个事件仅仅在文件被执行的第一时间被触发。
FAMStopExecuting        一个被监视的可执行文件运行终止了。如果一个可执行产生多个进程,则该事件只在最后一个进程终结的时候产生。
FAMCreated      一个被监视的目录中被创建了一个文件。
FAMAcknowledge  FAM产生一个FAMAcknowledge事件来响应一次FAMCancelMonitor()的调用。如果你指定了一个无效的请求,也就是说,一个相对路径,FAM自动取消这个请求并且立即发送一个FAMAcknowledge事件。
FAMExists       当应用程序请求的那个文件已经被监视,FAM为那个文件产生一个FAMExists事件(如果文件存在的话)。当你的应用程序请求的那个目录已经被监视时,FAM为那个目录以及目录下的每一个文件产生一个FAMExists事件。
FAMEndExist     当应用程序请求的文件或目录被监视时,FAM在最后一个FAMExists事件后产生一个FAMEndExist事件。(所以,如果你监视一个文件,FAM只产生一个FAMExists事件,随后产生FAMEndExist事件。)
————————————————-
注意:在IRIX 6.2之前,FAMNextEvent()没有在FAMEndExist事件中初始化filename字段。你应该使用要求码去寻找事件所参考的文件或目录。
————————————————-

5符号链接

如果你给FAMMonitorDirector()或FAMMonitorFile()所指明的路径文件名是一个符号链接,FAM仅仅监视符号链接自身,而不是符号链接的目标。虽然逻辑上可能感觉应自动监视符号链接的目标,但考虑到如果目标是一个自动挂载的文件系统,monitoring the target triggers and holds an automount。另一个用监视链接自身代替目标的理由是目标可能不存在。

没有一个通用的解决方法来处理监视符号链接的目标。你可以决定一个适合的方法用于你的应用程序去监视目标,即使它是自动挂载的。
————————————————-
提示:当你解决一个连接到链接的最终目标的情形时,libc例程realpath(3C)非常有用。
————————————————-
————————————————-
提示:使用statvfs(2)去识别一个远程文件。
————————————————-

另一方面,为了避免triggering and holding an automount,你可以手动的追踪符号链接,直到达到一个你可以监视的本地的目标。如果目标是不存在的文件系统,那么你应该决定不去监视目标。另一个选择是对目标进行一次测试,如果它存在(local),which triggers an automount only once if the target is automounted.

举个例子,下面的例程判定给定的路径是一个不存的、不稳定的链接、本地的还是远程的。
=================================================
#include<errno.h>
#include<limits.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/statvfs.h>
/*
 * determine a file’s location
 */
enum location {ERROR,NONEXISTENT,DANGLING,LOCAL,REMOTE};
enum location
file_location(const char *path)
{
        char target_path[PATH_MAX];
        struct stat statbuf;
        struct statvfs svfsbuf;

        if (!realpath(path,target_path))
        {
                /*
                 *realpath failed — probably a permission problem,
                 *dangling link or nonexistent file.
                 */
                if (errno==EACCES)
                        return ERROR;
                if (lstat(path,&statbuf)==0)
                        return DANGLING;
                else if (errno==ENOENT)
                        return NONEXISTENT;
                else
                        return ERROR;
        }
        /*
         * Realpath succeeded.Find out if file is local.
         */
        if (statvfs(target_path,&svfsbuf) <0)
                return ERROR;
        if (svfsbuf.f_flag &ST_LOCAL)
                return LOCAL;
        else
                return REMOTE;
}
=================================================

6FAM例子

下面的例子展示了在某些特定情形下FAM发送的事件流。

例子:一个客户端监视一个存在的文件。稍后,另外一个程序在被监视的文件上追加了数据。再随后,客户端取消了对监视的请求。
=================================================
User calls      FAMMonitorFile(… "/a/b/c"…)
FAM events:     FAMExists       /a/b/c
                FAMEndExist     /a/b/c

Other program appends to file.
FAM event:      FAMChanged      /a/b/c

User calls      FAMCancelMonitor(…)
FAM event:      FAMAcknowledge  /a/b/c
=================================================

例子:一个客户端监视了一个包含有两个文件的目录。稍后,另一个程序创建了第三个文件。
=================================================
User calls      FAMMonitorDirectory(…"/a/b"…)
FAM events:     FAMExists       /a/b
                FAMExists       file_one
                FAMExists       file_two
                FAMEndExist     /a/b
Third file created.
                FAMCreated      file_three
=================================================

例子:一个客户端监视一个已经执行的可执行文件。稍后,这个程序退出了。
=================================================
User calls      FAMMonitorFile(…"/a/b/program"…)
FAM events:     FAMExists       /a/b/program
                FAMEndExist     /a/b/program
                FAMStartExecuting /a/b/program
Program exits.
FAM event:      FAMStopExecuting /a/b/program
=================================================

例子:一个客户端做了一次无效的请求。
=================================================
User calls      FAMMonitorDirectory(…"relative/path"…)
FAM event:      FAMAcknowledge relative/path
=================================================

例子:一个客户端监视了一个不存在的文件,稍后,另一个程序创建了这个文件。
=================================================
User calls      FAMMonitorFile(…"/a/b/c"…)
FAM events:     FAMDeleted      /a/b/c
                FAMEndExist
File is created.
FAM event:      FAMCreated      /a/b/c
=================================================

例子:一个客户端监视一个含有一些文件的目录。另一个程序删除了这个目录,然后又创建了一个和改目录同名的文件。
=================================================
User calls      FAMMonitorDirectory(…"/a/b"…)
FAM events:     FAMExists       /a/b
                FAMExists       file_one
                FAMExists       file_two
                FAMEndExist     /a/b
Directory and files are deleted.
FAM events:     FAMDeleted      /a/b
                FAMChanged      /a/b
                FAMDeleted      file_one
                FAMDEleted      file_two
File with same name created.
FAM events:     FAMCreated      /a/b
                FAMChanged      /a/b
================================================

7使用FAM

如同“侦测文件和目录的改变”里写的,你的应用程序可以检查通过两种方法监视的文件和目录的变化。

        ×使用select()去等待直到FAM socket激活,指明一个改变,它被描述在“等待文件改变”。

        ×使用FAMPending()去周期的查询(poll)FAM,它被解释在“轮询(Polling)文件改变”

这一节描述了如何使用这两种方法。

7.1等待文件改变

在你的应用程序中使用下面的步骤,使用的是select方发去检测文件的改变。

        1.调用FAMOpen()创建一个到fam的连接。这个例程返回一个将被用于所有FAM进程的FAMConnection结构体。
        2.调用FAMMonitorFile()和FAMMonitorDirectory()去告知fam哪些文件和目录被监视。
        3.当fam socket是可读时,选择在fam socket上的文件描述符并调用FAMNextEvent()。
        4.当应用程序完成对一个文件或目录的监视,调用FAMCancelMonitor()。如果你想临时暂停监视一个文件或目录,调用FAMSuspendMonitor()。当你准备再次开始监视时,调用FAMResumeMonitor()。
        5.当应用程序不再需要对文件和目录监视时,调用FAMClose()去释放与文件被监视的相关的资源。关闭到fam的连接,这一步是可选的,如果你简单的退出你的应用程序。

例子8-1在一个简单的程序中演示了这一过程。

例子8-1.对FAM使用Select
===================================================
/*
 * monitor.c–monitor arbitrary file or directory using fam
 */
#include <fam.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/select.h>

/*event_name() – return printable name of fame event code */

const char *event_name(int code)
{
        static const char *famevent[]={
                "",
                "FAMDeleted",
                "FAMStartExecuting",
                "FAMStopExecuting",
                "FAMCreated",
                "FAMMoved",
                "FAMAcknowledge",
                "FAMExists",
                "FAMEndExist"
        };
        static char unknow_event[10];

        if (code < FAMChaged || code > FAMEndExist)
        {
                sprintf(unknow_event,"unknow (%d)",code);
                return unknown_event;
        }
        return famevent ;
}

void main(int argc,char *argv[])
{
        int i,nmon,rc,fam_fd;
        FAMConnection fc;
        FAMRequest *frp;
        struct stat status;
        fd_set readfds;

        /*Allocate storage for requests */

        frp=malloc(argc * sizeof *frp);
        if (!frp)
        {
                perror("malloc");
                exit(1);
        }

        /* Open fam connection */

        if ((FAMOpen(&fc)) < 0)
        {
                perror("fam");
                exit(1);
        }

        /*Reuqest monitoring for each program argument */

        for (nmon=0,i=1;i<argc;i++)
        {
                if (stat(argv[i],&status) < 0)
                {
                        perror(argv[i]);
                        status.st_mode=0;
                }
                if ((status.st_mode & S_IFMT)==S_IFDIR)
                        rc=FAMMonitorDirectory(&fc,argv[i],frp+i,NULL);
                else
                        rc=FAMMonitorFile(&fc,argv[i],frp+i,NULL);
                if (rc < 0)
                {
                        perror("FAMMonitor failed");
                        continue;
                }
                nmon++;
        }
        if (!nmon)
        {
                fprintf(stderr,"Nothing monitored.n");
                exit(1);
        }

        /*Initialize select data structure */
        fam_fd=FAMCONNECTION_GETfd(&fc);
        FD_ZERO(&readfds);
        FD_SET(fam_fd,&readfds);

        /*Loop forever. */tic char unknow_even

        while(1)
        {
                if (select(fam_fd + 1,&readfds,NULL,NULL,NULL) < 0)
                {
                        perror("select failed");
                        exit(1);
                }
                if (FD_ISSET(fam_fd,&readfds))
                {
                        if (FAMNextEvent(&fc,&fe) < 0)
                        {
                                perror("FAMNextEvent");
                                exit(1);
                        }
                        printf("%-24s %sn",fe.filename,event_name(fe.code));
                }
        }
}
================================================

7.2轮询(Polling)文件改变

在你的应用程序中遵循下面的步骤使用FAM,使用的是轮询的方法去侦测文件的改变。

        1.调用FAMOpen()去创建一个到fam的连接。这个例程返回一个以后所有FAM进程都要用到的FAMConnection结构体。
        2.调用FAMMonitorFile()和FAMMonitorDirectory()去告知fam哪些文件和目被监视。
        3.当有一个pending FAM事件时,调用FAMPending()去监测,如果一个事件被侦测到,则调用FAMNextEvent()。
        4.当应用程序完成监视一个文件或目录时,调用FAMCancelMonitor()。如果想临时暂停对一个文件或目录的监视,调用FAMSuspendMonitor()。当你准备再次开始监视时,调用FAMResumeMonitor()。
        5.当应用程序不再需要监视文件和目录时,调用FAMClose()去释放文件被监视时的相关资源并且关闭到fam的连接。这一步是可选的,如果你简单的推出你的应用程序。

举例,你可以通过删除掉例8-1中关于select data structure的代码并且用例8-2中的代码替换调while loop来在monitor.c程序中使用轮询(polling)方法。这个简单的程序演示了这个过程。

例8-2.对FAM使用Polling方法
==================================================
while(1)
{
        rc=FAMPending(&fc);
        if (rc ==0)
                break;
        else if(rc==-1)
                perror ("FAMPending");
        if (FAMNextEvent(&fc,&fe) < 0)
        {
                perror ("FAMNextEvent");
                exit(1);
        }
        printf("%-24s %sn",fe.filename,event_name(fe.code));
}
==================================================

当你想要在Xt工作过程中使用轮询来查询改变,这是一个非常有用的方法。例8-3现实了这种工作过程的基本代码。

例8-3.在Xt工作过程中使用轮询FAM
==================================================
Boolean monitorFiles(XtPointer clientData)
{
        int rc=FAMPending(&fc);

        if (rc == 0)
                return(FALSE);
        else if (rc == -1)
                XtAppError(app_context,"FAMPending error");

        if (FAMNextEvent(&fc,&fe) < 0)
        {
                XtAppError(app_context,"FAMNextEvent error");
        }

        handleFileChange(fe);
        return(FALSE);
}
===================================================

Write a Comment

Comment