inotify — Linux 2.6 内核中的文件系统变化通知机制

一、 引言

众所周知,Linux 桌面系统与 MAC 或 Windows 相比有许多不如人意的地方,为了改善这种状况,开源社区提出用户态需要内核提供一些机制,以便用户态能够及时地得知内核或底层硬件设备发生了什么,从而能 够更好地管理设备,给用户提供更好的服务,如 hotplug、udev 和 inotify 就是这种需求催生的。Hotplug 是一种内核向用户态应用通报关于热插拔设备一些事件发生的机制,桌面系统能够利用它对设备进行有效的管理,udev 动态地维护 /dev 下的设备文件,inotify 是一种文件系统的变化通知机制,如文件增加、删除等事件可以立刻让用户态得知,该机制是著名的桌面搜索引擎项目 beagle 引入的,并在 Gamin 等项目中被应用。

事实上,在 inotify 之前已经存在一种类似的机制叫 dnotify,但是它存在许多缺陷:

1. 对于想监视的每一个目录,用户都需要打开一个文件描述符,因此如果需要监视的目录较多,将导致打开许多文件描述符,特别是,如果被监视目录在移动介质上 (如光盘和 USB 盘),将导致无法 umount 这些文件系统,因为使用 dnotify 的应用打开的文件描述符在使用该文件系统。

2. dnotify 是基于目录的,它只能得到目录变化事件,当然在目录内的文件的变化会影响到其所在目录从而引发目录变化事件,但是要想通过目录事件来得知哪个文件变化,需要缓存许多 stat 结构的数据。

3. Dnotify 的接口非常不友好,它使用 signal。

Inotify 是为替代 dnotify 而设计的,它克服了 dnotify 的缺陷,提供了更好用的,简洁而强大的文件变化通知机制:

1. Inotify 不需要对被监视的目标打开文件描述符,而且如果被监视目标在可移动介质上,那么在 umount 该介质上的文件系统后,被监视目标对应的 watch 将被自动删除,并且会产生一个 umount 事件。

2. Inotify 既可以监视文件,也可以监视目录。

3. Inotify 使用系统调用而非 SIGIO 来通知文件系统事件。

4. Inotify 使用文件描述符作为接口,因而可以使用通常的文件 I/O 操作select 和 poll 来监视文件系统的变化。

Inotify 可以监视的文件系统事件包括:

  • IN_ACCESS,即文件被访问
  • IN_MODIFY,文件被 write
  • IN_ATTRIB,文件属性被修改,如 chmod、chown、touch 等
  • IN_CLOSE_WRITE,可写文件被 close
  • IN_CLOSE_NOWRITE,不可写文件被 close
  • IN_OPEN,文件被 open
  • IN_MOVED_FROM,文件被移走,如 mv
  • IN_MOVED_TO,文件被移来,如 mv、cp
  • IN_CREATE,创建新文件
  • IN_DELETE,文件被删除,如 rm
  • IN_DELETE_SELF,自删除,即一个可执行文件在执行时删除自己
  • IN_MOVE_SELF,自移动,即一个可执行文件在执行时移动自己
  • IN_UNMOUNT,宿主文件系统被 umount
  • IN_CLOSE,文件被关闭,等同于(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
  • IN_MOVE,文件被移动,等同于(IN_MOVED_FROM | IN_MOVED_TO)

注:上面所说的文件也包括目录。



回页首

二、用户接口

在用户态,inotify 通过三个系统调用和在返回的文件描述符上的文件 I/ 操作来使用,使用 inotify 的第一步是创建 inotify 实例:

int fd = inotify_init ();

每一个 inotify 实例对应一个独立的排序的队列。

文件系统的变化事件被称做 watches 的一个对象管理,每一个 watch 是一个二元组(目标,事件掩码),目标可以是文件或目录,事件掩码表示应用希望关注的 inotify 事件,每一个位对应一个 inotify 事件。Watch 对象通过 watch描述符引用,watches 通过文件或目录的路径名来添加。目录 watches 将返回在该目录下的所有文件上面发生的事件。

下面函数用于添加一个 watch:

int wd = inotify_add_watch (fd, path, mask);

fd 是 inotify_init() 返回的文件描述符,path 是被监视的目标的路径名(即文件名或目录名),mask 是事件掩码, 在头文件 linux/inotify.h 中定义了每一位代表的事件。可以使用同样的方式来修改事件掩码,即改变希望被通知的inotify 事件。Wd 是 watch 描述符。

下面的函数用于删除一个 watch:

int ret = inotify_rm_watch (fd, wd);

fd 是 inotify_init() 返回的文件描述符,wd 是 inotify_add_watch() 返回的 watch 描述符。Ret 是函数的返回值。

文件事件用一个 inotify_event 结构表示,它通过由 inotify_init() 返回的文件描述符使用通常文件读取函数 read 来获得


struct inotify_event {
__s32 wd; /* watch descriptor */
__u32 mask; /* watch mask */
__u32 cookie; /* cookie to synchronize two events */
__u32 len; /* length (including nulls) of name */
char name[0]; /* stub for possible name */
};

结构中的 wd 为被监视目标的 watch 描述符,mask 为事件掩码,len 为 name字符串的长度,name 为被监视目标的路径名,该结构的 name 字段为一个桩,它只是为了用户方面引用文件名,文件名是变长的,它实际紧跟在该结构的后面,文件名将被 0 填充以使下一个事件结构能够 4 字节对齐。注意,len 也把填充字节数统计在内。

通过 read 调用可以一次获得多个事件,只要提供的 buf 足够大。

size_t len = read (fd, buf, BUF_LEN);

buf 是一个 inotify_event 结构的数组指针,BUF_LEN 指定要读取的总长度,buf 大小至少要不小于 BUF_LEN,该调用返回的事件数取决于 BUF_LEN 以及事件中文件名的长度。Len 为实际读去的字节数,即获得的事件的总长度。

可以在函数 inotify_init() 返回的文件描述符 fd 上使用 select() 或poll(), 也可以在 fd 上使用 ioctl 命令 FIONREAD 来得到当前队列的长度。close(fd)将删除所有添加到 fd 中的 watch 并做必要的清理。

int inotify_init (void);
int inotify_add_watch (int fd, const char *path, __u32 mask);
int inotify_rm_watch (int fd, __u32 mask);



回页首

三、内核实现机理

在内核中,每一个 inotify 实例对应一个 inotify_device 结构:

struct inotify_device {
wait_queue_head_t wq; /* wait queue for i/o */
struct idr idr; /* idr mapping wd -> watch */
struct semaphore sem; /* protects this bad boy */
struct list_head events; /* list of queued events */
struct list_head watches; /* list of watches */
atomic_t count; /* reference count */
struct user_struct *user; /* user who opened this dev */
unsigned int queue_size; /* size of the queue (bytes) */
unsigned int event_count; /* number of pending events */
unsigned int max_events; /* maximum number of events */
u32 last_wd; /* the last wd allocated */
};

wq 是等待队列,被 read 调用阻塞的进程将挂在该等待队列上,idr 用于把 watch 描述符映射到对应的 inotify_watch,sem 用于同步对该结构的访问,events 为该 inotify 实例上发生的事件的列表,被该 inotify 实例监视的所有事件在发生后都将插入到这个列表,watches 是给 inotify 实例监视的 watch 列表,inotify_add_watch 将把新添加的 watch 插入到该列表,count 是引用计数,user 用于描述创建该 inotify 实例的用户,queue_size 表示该 inotify 实例的事件队列的字节数,event_count 是 events 列表的事件数,max_events 为最大允许的事件数,last_wd 是上次分配的 watch 描述符。

每一个 watch 对应一个 inotify_watch 结构:

struct inotify_watch {
struct list_head d_list; /* entry in inotify_device’s list */
struct list_head i_list; /* entry in inode’s list */
atomic_t count; /* reference count */
struct inotify_device *dev; /* associated device */
struct inode *inode; /* associated inode */
s32 wd; /* watch descriptor */
u32 mask; /* event mask for this watch */
};

d_list 指向所有 inotify_device 组成的列表的,i_list 指向所有被监视 inode 组成的列表,count 是引用计数,dev 指向该 watch 所在的 inotify 实例对应的 inotify_device 结构,inode 指向该 watch 要监视的 inode,wd 是分配给该 watch 的描述符,mask 是该 watch 的事件掩码,表示它对哪些文件系统事件感兴趣。

结 构 inotify_device 在用户态调用 inotify_init() 时创建,当关闭 inotify_init()返回的文件描述符时将被释放。结构 inotify_watch 在用户态调用 inotify_add_watch()时创建,在用户态调用 inotify_rm_watch() 或 close(fd) 时被释放。

无论是目录还是文件,在内核中都对应一个 inode 结构,inotify 系统在 inode 结构中增加了两个字段:

#ifdef CONFIG_INOTIFY
struct list_head inotify_watches; /* watches on this inode */
struct semaphore inotify_sem; /* protects the watches list */
#endif

inotify_watches 是在被监视目标上的 watch 列表,每当用户调用 inotify_add_watch()时,内核就为添加的 watch 创建一个 inotify_watch 结构,并把它插入到被监视目标对应的 inode 的 inotify_watches 列表。inotify_sem 用于同步对 inotify_watches 列表的访问。当文件系统发生第一部分提到的事件之一时,相应的文件系统代码将显示调用fsnotify_* 来把相应的事件报告给 inotify 系统,其中*号就是相应的事件名,目前实现包括:

  • fsnotify_move,文件从一个目录移动到另一个目录
  • fsnotify_nameremove,文件从目录中删除
  • fsnotify_inoderemove,自删除
  • fsnotify_create,创建新文件
  • fsnotify_mkdir,创建新目录
  • fsnotify_access,文件被读
  • fsnotify_modify,文件被写
  • fsnotify_open,文件被打开
  • fsnotify_close,文件被关闭
  • fsnotify_xattr,文件的扩展属性被修改
  • fsnotify_change,文件被修改或原数据被修改

有一个例外情况,就是 inotify_unmount_inodes,它会在文件系统被 umount 时调用来通知 umount 事件给 inotify 系统。

以上提到的通知函数最后都调用 inotify_inode_queue_event(inotify_unmount_inodes直接调用 inotify_dev_queue_event ),该函数首先判断对应的inode是否被监视,这通过查看 inotify_watches 列表是否为空来实现,如果发现 inode 没有被监视,什么也不做,立刻返回,反之,遍历 inotify_watches 列表,看是否当前的文件操作事件被某个 watch 监视,如果是,调用 inotify_dev_queue_event,否则,返回。函数inotify_dev_queue_event 首先判断该事件是否是上一个事件的重复,如果是就丢弃该事件并返回,否则,它判断是否 inotify 实例即 inotify_device 的事件队列是否溢出,如果溢出,产生一个溢出事件,否则产生一个当前的文件操作事件,这些事件通过kernel_event 构建,kernel_event 将创建一个 inotify_kernel_event 结构,然后把该结构插入到对应的 inotify_device 的 events 事件列表,然后唤醒等待在inotify_device 结构中的 wq 指向的等待队列。想监视文件系统事件的用户态进程在inotify 实例(即 inotify_init() 返回的文件描述符)上调用 read 时但没有事件时就挂在等待队列 wq 上。



回页首

四、使用示例

下面是一个使用 inotify 来监视文件系统事件的例子:

#include <linux/unistd.h>
#include <linux/inotify.h>
#include <errno.h>
_syscall0(int, inotify_init)
_syscall3(int, inotify_add_watch, int, fd, const char *, path, __u32, mask)
_syscall2(int, inotify_rm_watch, int, fd, __u32, mask)
char * monitored_files[] = {
"./tmp_file",
"./tmp_dir",
"/mnt/sda3/windows_file"
};
struct wd_name {
int wd;
char * name;
};
#define WD_NUM 3
struct wd_name wd_array[WD_NUM];
char * event_array[] = {
"File was accessed",
"File was modified",
"File attributes were changed",
"writtable file closed",
"Unwrittable file closed",
"File was opened",
"File was moved from X",
"File was moved to Y",
"Subfile was created",
"Subfile was deleted",
"Self was deleted",
"Self was moved",
"",
"Backing fs was unmounted",
"Event queued overflowed",
"File was ignored"
};
#define EVENT_NUM 16
#define MAX_BUF_SIZE 1024

int main(void)
{
int fd;
int wd;
char buffer[1024];
char * offset = NULL;
struct inotify_event * event;
int len, tmp_len;
char strbuf[16];
int i = 0;

fd = inotify_init();
if (fd < 0) {
printf("Fail to initialize inotify.n");
exit(-1);
}
for (i=0; i<WD_NUM; i++) {
wd_array[i].name = monitored_files[i];
wd = inotify_add_watch(fd, wd_array[i].name, IN_ALL_EVENTS);
if (wd < 0) {
printf("Can’t add watch for %s.n", wd_array[i].name);
exit(-1);
}
wd_array[i].wd = wd;
}
while(len = read(fd, buffer, MAX_BUF_SIZE)) {
offset = buffer;
printf("Some event happens, len = %d.n", len);
event = (struct inotify_event *)buffer;
while (((char *)event – buffer) < len) {
if (event->mask & IN_ISDIR) {
memcpy(strbuf, "Direcotory", 11);
}
else {
memcpy(strbuf, "File", 5);
}
printf("Object type: %sn", strbuf);
for (i=0; i<WD_NUM; i++) {
if (event->wd != wd_array[i].wd) continue;
printf("Object name: %sn", wd_array[i].name);
break;
}
printf("Event mask: %08Xn", event->mask);
for (i=0; i<EVENT_NUM; i++) {
if (event_array[i][0] == ”) continue;
if (event->mask & (1<<i)) {
printf("Event: %sn", event_array[i]);
}
}
tmp_len = sizeof(struct inotify_event) + event->len;
event = (struct inotify_event *)(offset + tmp_len);
offset += tmp_len;
}
}
}

该程序将监视发生在当前目录下的文件 tmp_file 与当前目录下的目录 tmp_dir 上的所有文件系统事件, 同时它也将监视发生在文件 /mnt/sda3/windows_file 上的文件系统事件,注意,/mnt/sda3 是 SATA 硬盘分区 3 的挂接点。

细心的读者可能注意到,该程序首部使用 _syscallN 来声明 inotify 系统调用,原因是这些系统调用是在最新的稳定内核 2.6.13 中引入的,glibc 并没有实现这些系统调用的库函数版本,因此,为了能在程序中使用这些系统调用,必须通过 _syscallN 来声明这些新的系统,其中的 N 为要声明的系统调用实际的参数数。还有需要注意的地方是系统的头文件必须与被启动的内核匹配,为了让上面的程序能够成功编译,必须让 2.6.13 的内核头文件(包括 include/linux/*, include/asm/* 和 include/asm-generic/*)在头文件搜索路径内,并且是第一优先搜索的头文件路径,因为 _syscallN 需要用到这些头文件中的 linux/unistd.h 和 asm/unistd.h,它们包含了 inotify 的三个系统调用的系统调用号 __NR_inotify_init、__NR_inotify_add_watch 和 __NR_inotify_rm_watch。

因此,要想成功编译此程序,只要把用户编译好的内核的头文件拷贝到该程序所在的路径,并使用如下命令编译即可:

$gcc -o inotify_example -I. inotify_example.c

注意:当前目录下应当包含 linux、asm 和 asm-generic 三个已编译好的 2.6.13 内核的有文件目录,asm 是一个链接,因此拷贝 asm 头文件的时候需要拷贝 asm 与 asm-ARCH(对于 x86 平台应当是 asm-i386)。 然后,为了运行该程序,需要在当前目录下创建文件 tmp_file 和目录 tmp_dir,对于/mnt/sda3/windows_file 文件,用户需要依自己的实际情况而定,可能是/mnt/dosc/windows_file,即 /mnt/dosc 是一个 FAT32 的 windows 硬盘,因此用户在编译该程序时需要根据自己的实际情况来修改 /mnt/sda3。Windows_file 是在被 mount 硬盘上创建的一个文件,为了运行该程序,它必须被创建。

以下是作者在 redhat 9.0 上运行此程序得到的一些结果:

当运行此程序的时候在另一个虚拟终端执行 cat ./tmp_file,此程序的输出为:

Some event happens, len = 48.
Object type: File
Object name: ./tmp_file
Event mask: 00000020
Event: File was opened
Object type: File
Object name: ./tmp_file
Event mask: 00000001
Event: File was accessed
Object type: File
Object name: ./tmp_file
Event mask: 00000010
Event: Unwrittable file closed

以上事件清楚地说明了 cat 指令执行了文件 open 和 close 操作,当然 open 和 close操作都属于 access 操作,任何对文件的操作都是 access 操作。

此外,运行 vi ./tmp_file,发现 vi实际在编辑文件时复制了一个副本,在未保存之前是对副本进行操作。 运行 vi ./tmp_file, 修改并保存退出时,发现 vi 实际在保存修改时删除了最初的文件并把那个副本文件名更改为最初的文件的名称。注意,事件"File was ignored"表示系统把该文件对应的 watch 从 inotify 实例的 watch 列表中删除,因为文件已经被删除。 读者可以自己分别执行命令:echo "abc" > ./tmp_file 、rm -f tmp_file、 ls tmp_dir、 cd tmp_dir;touch c.txt、 rm c.txt 、 umount /mnt/sda3(实际用户需要使用自己当时的 mount 点路径名),然后分析一下结果。Umount 触发两个事件,一个表示文件已经被删除或不在存在,另一个表示该文件的 watch被从 watch 列表中删除。



回页首

五、典型应用

beagle 是 GNOME 的桌面搜索引擎项目,inotify 的引入就是完全受它的驱动而做的。对于桌面搜索引擎,它一般作为一个优先级很低的后台进程运行, 只有在系统没有其他任务可运行时才被调度执行,桌面搜索引擎的主要用途就是为系统的文件系统的文件建立索引数据库,以便用户在需要某文件但又想不起存放在 哪里时能够根据某些关键字或特征快速地搜索到需要的文件,就象使用网络搜索引擎 google 一样便捷。文件系统有个特点就是只有某些文件会变化,因此桌面搜索引擎在第一次建立完索引数据库后,没必要重复遍历所有的文件建立新的索引,它只需要更新 修改了的文件的索引,建立新增加的文件的索引,删除已经删除的文件的索引就足够了,这样桌面搜索引擎需要做的工作就大大地减少。Inotify 就是为这一意图专门设计的,beagle 为需要监视的目录或文件创建了inotify 实例,然后它就等待该 inotify 上发生文件系统事件,如果没有任何文件变化,beagle 将不需要任何开销,只有在有被监视的事件发生时,beagle 才被唤醒并根据实际事件来更新对应的文件的索引,然后继续睡眠等待下一个文件系统事件发生。在 SuSe 9.3 和即将发布的 10.0 中就包含了该桌面搜索引擎,它能够为文档、email、音乐、图象和应用等建立索引。使用过 windows 下的桌面搜索引擎的读者对 google 和 yahoo 以及 Microsoft 的桌面搜索引擎有深刻的体会,感兴趣读者可以安装 SuSe 使用一下。



回页首

六、小结

inotify 是在 2.6.13 中引入的新功能,它为用户态监视文件系统的变化提供了强大的支持,本文详尽地介绍了其起源、内核实现、用户接口以及使用,有兴趣的读者可以读 2.6.13的相关源码来进一步了解其实现细节。

csync2 is so cool

When you search csync2 on google, you’ll get a hint:

Did you mean: sync2

That is so unfair. csync2 is one of the coolest tool to do Server Farm Synchronization among what I have tried. It solved so many problems I had before. Working as a sys admin, administrating a big server farm with hundres of linux machines, how to synchronize the data is always a big headache. You can use your own script to scp, you can use rsync, you can use subversion. Yeah, there are so many tools out there you can utilize. But, none of them are built for server synchronization.

You can also use SAN, yeah, that would be nice. But SAN solution is not cheap. You know that, right?

Ok, let’s have a look at csync2. the full name is "cluster synchronization tool, 2nd generation". You can visit their website: http://oss.linbit.com/csync2/. Basicly everything you need is over there. But you’ll noticed there’s only one doc available: http://oss.linbit.com/csync2/paper.pdf.
The author Clifford Wolf

One advantage building from source here is the part to build a certificate, notice the line make cert;, just that, your certificate is made.

echo "csync2 30865/tcp" >> /etc/services

Be careful about turning on the xinetd service though. You may want to double check your /etc/xinetd.d/, make sure no other unwanted services would be turned on by this.

Now you are ready to go. Next thing you need is a good config file.

FYI: the default config file csync2 uses is /etc/csync2.cfg. Believe it or not, I didn’t find it on the paper.pdf. it took me quite a while to figure out that one is the default one.

Here is a sample /etc/csync2.cfg

group serverfarm
{
host server34.domain.com;
host (server35.domain.com);
host (server36.domain.com);
host (server37.domain.com);

key /etc/serverfarm.key;

include /etc/hosts;
include /etc/csync2.cfg;
include /usr/local/apache2/conf;
include /var/www;

action
{
pattern /usr/local/apache2/conf/httpd.conf;
exec "/usr/local/apache2/bin/apachectl graceful";
logfile "/var/log/csync2_action.log";
do-local;
}

backup-directory /var/backups/csync2;
backup-generations 3;

auto none;
}

I am only synchronizing the hosts file, the csync2.cfg file, the httpd.conf file, and the server document root. Notice the backup-directory, that directory, the csync2 won’t create for you, and it will complain some weird error if you don’t create them by yourself. So do that now.

This line: key /etc/serverfarm.key;
that’s their preshared key. generate is in any machine with:
csync2 -k /etc/serverfarm.key, and synchronize it to all your other machines. hopefully this is the last time you do a sync use your stone age solution, maybe rsync?

The coolest part IMO is the action part.
pattern /usr/local/apache2/conf/httpd.conf;
exec "/usr/local/apache2/bin/apachectl graceful";
This means whenever I change the httpd.conf file, it’ll restart the apache for me. How nice!

Notice also I put () for most servers. That means, those servers are just slaves. well, it’s a server farm, who’s gonna change things in slaves if not for updating code? this also solves the conflict problem. Who cares who changed sth in slave machines, server34 is the one I need to put code on and propagate!

Now everything is set, ready… Go, let’s make some test.

First time sync, according to the author, need to run something like -I. But in my case, I just ran a csync2 -x on server34. There are lots of conflicts, sure. but my setting is only server34 should win, so did that machine win. The first time sync make take a while, not much.

Then I added a virtual host on server34, modifed httpd.conf, added the documentroot at /var/www/dummy-host, put some files in there, then I issued again the csync2 -x, I counted, 1,2,3,4,5, when I counted to 5, the execution finished, without any message.

Then try the new virtual host name in your browser, wow, it’s there, refresh, refresh, no missing server, they are all synced. only 5 seconds, 60 servers, that’s easy!

Now I hope you get an idea how to use this fantastic tool. Enjoy! :)

使用 inotify 监控文件系统的活动

系统管理就像日常生活一样。就像刷牙和吃蔬菜一样,日常的维护能保持机器的良好状态。您必须定期清空废物,比如临时文件或无用的日志文件,以及花时 间填写表单、回复电话、下载更新和监控进程等。幸好自动化 shell 脚本、使用 Nagios 等工具进行监控、通过常见的 cron 进行任务调度可以减轻这个负担。

但奇怪的是,这些工具没有一个具有响应性。当然,您可以安排一个频繁运行的 cron 任务来监控条件,但这样繁忙的轮询 — 消耗大量资源并且具有不确定性 — 并不是很理想。例如,如果您必须监控输入数据的几个 Transfer Protocol(FTP)收存箱,您可能要通过 find 命令扫描每个目标目录,列举新的内容。然而,尽管这个操作看起来并没有什么害处,但每个调用都产生一个新的 shell 和 find 命令,这需要许多系统调用来打开目录,然后扫描目录,等等。这会造成过于频繁的或大量的轮询任务(更糟糕的是,繁忙的轮询并不总是很好。想象一下一个文件系统浏览器,比如 Mac OS X 的 Finder,轮询更新时需要的大量资源及其复杂性)。

那么,管理员应该怎么办呢?令人高兴的是,您可以再次求助于可以信赖的计算机。

了解 inotify

Inotify 是一个 Linux 内核特性,它监控文件系统,并且及时向专门的应用程序发出相关的事件警告,比如删除、读、写和卸载操作等。您还可以跟踪活动的源头和目标等细节。

使用 inotify 很简单:创建一个文件描述符,附加一个或多个监视器(一个监视器 是一个路径和一组事件),然后使用 read() 方法从描述符获取事件信息。read() 并不会用光整个周期,它在事件发生之前是被阻塞的。

更好的是,因为 inotify 通过传统的文件描述符工作,您可以利用传统的 select() 系统调用来被动地监控监视器和许多其他输入源。两种方法 — 阻塞文件描述符和使用 select()— 都避免了繁忙轮询。

现在,让我们深入了解 inotify,写一些 C 代码,然后看看一组命令行工具,您可以构建并使用它们将命令和脚本附加到文件系统事件。Inotify 不会在中途失去控制,但它可以运行 catwget,并且在必要时严格执行。

要使用 inotify,您必须具备一台带有 2.6.13 或更新内核的 Linux 机器(以前的 Linux 内核版本使用更低级的文件监控器 dnotify)。如果您不知道内核的版本,请转到 shell,输入 uname -a

% uname -a
Linux ubuntu-desktop 2.6.24-19-generic #1 SMP … i686 GNU/Linux

如果列出的内核版本不低于 2.6.13,您的系统就支持 inotify。您还可以检查机器的 /usr/include/sys/inotify.h 文件。如果它存在,表明您的内核支持 inotify。

注意:FreeBSD 和 Mac OS X 提供一个类似于 inotify 的 kqueue。在 FreeBSD 机器上输入 man 2 kqueue 获取更多信息。

本文基于 Ubuntu Desktop version 8.04.1(即 Hardy),它运行在 Mac OS X version 10.5 Leopard 的 Parallels Desktop version 3.0。



回页首

inotify C API

Inotify 提供 3 个系统调用,它们可以构建各种各样的文件系统监控器:

  • inotify_init() 在内核中创建 inotify 子系统的一个实例,成功的话将返回一个文件描述符,失败则返回 -1。就像其他系统调用一样,如果 inotify_init() 失败,请检查 errno 以获得诊断信息。
  • 顾名思义,inotify_add_watch() 用于添加监视器。每个监视器必须提供一个路径名和相关事件的列表(每个事件由一个常量指定,比如 IN_MODIFY)。要监控多个事件,只需在事件之间使用逻辑操作符— C 语言中的管道线(|)操作符。如果 inotify_add_watch() 成功,该调用会为已注册的监视器返回一个惟一的标识符;否则,返回 -1。使用这个标识符更改或删除相关的监视器。
  • inotify_rm_watch() 删除一个监视器。

此外,还需要 read()close() 系统调用。如果描述符由 inotify_init() 生成,则调用 read() 等待警告。假设有一个典型的文件描述符,应用程序将阻塞对事件的接收,这些事件在流中表现为数据。文件描述符上的由 inotify_init() 生成的通用 close() 删除所有活动监视器,并释放与 inotify 实例相关联的所有内存(这里也用到典型的引用计数警告。与实例相关联的所有文件描述符必须在监视器和 inotify 消耗的内存被释放之前关闭)。

这个强大的工具提供 3 个应用程序编程接口(API)调用,以及简单、熟悉的范例 “所有内容都是文件”。现在,我们看看示例应用程序。

示例应用程序:事件监控

清单 1 是一个监控两个事件的目录的简短 C 程序:文件的创建和删除。

清单 1. 简单的 inotify 应用程序,它监控创建、删除和修改事件的目录
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/inotify.h>

#define EVENT_SIZE ( sizeof (struct inotify_event) )
#define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )

int main( int argc, char **argv )
{
int length, i = 0;
int fd;
int wd;
char buffer[BUF_LEN];

fd = inotify_init();

if ( fd < 0 ) {
perror( "inotify_init" );
}

wd = inotify_add_watch( fd, "/home/strike",
IN_MODIFY | IN_CREATE | IN_DELETE );
length = read( fd, buffer, BUF_LEN );

if ( length < 0 ) {
perror( "read" );
}

while ( i < length ) {
struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ];
if ( event->len ) {
if ( event->mask & IN_CREATE ) {
if ( event->mask & IN_ISDIR ) {
printf( "The directory %s was created.n", event->name );
}
else {
printf( "The file %s was created.n", event->name );
}
}
else if ( event->mask & IN_DELETE ) {
if ( event->mask & IN_ISDIR ) {
printf( "The directory %s was deleted.n", event->name );
}
else {
printf( "The file %s was deleted.n", event->name );
}
}
else if ( event->mask & IN_MODIFY ) {
if ( event->mask & IN_ISDIR ) {
printf( "The directory %s was modified.n", event->name );
}
else {
printf( "The file %s was modified.n", event->name );
}
}
}
i += EVENT_SIZE + event->len;
}

( void ) inotify_rm_watch( fd, wd );
( void ) close( fd );

exit( 0 );
}

这个应用程序通过 fd = inotify_init(); 创建一个 inotify 实例,并添加一个监视器来监控修改、新文件和 /home/strike 中的损坏文件(由 wd = inotify_add_watch(...) 指定)。read() 方法在一个或多个警告到达之前是被阻塞的。警告的详细内容 — 每个文件、每个事件 — 是以字节流的形式发送的;因此,应用程序中的循环将字节流转换成一系列事件结构。

在文件 /usr/include/sys/inotify.h. 中,您可以找到事件结构的定义,它是一种 C 结构,如清单 2 所示。

清单 2. 事件结构的定义
struct inotify_event
{
int wd; /* The watch descriptor */
uint32_t mask; /* Watch mask */
uint32_t cookie; /* A cookie to tie two events together */
uint32_t len; /* The length of the filename found in the name field */
char name __flexarr; /* The name of the file, padding to the end with NULs */
}

wd 字段是指与事件相关联的监视器。如果每个 inotify 有一个以上的实例,您可以使用这个字段确定如何继续以后的处理过程。mask 字段由几个部分组成,它说明发生的事情。分别测试每个部分。

当把一个文件从一个目录移动到另一个目录时,您可以使用 cookie 将两个事件绑在一起。仅当您监视源和目标目录时,inotify 才生成两个移动事件 — 分别针对源和目标 —,并通过设置 cookie 将它们绑定在一起。要监视一个移动操作,必须指定 IN_MOVED_FROMIN_MOVED_TO,或使用简短的 IN_MOVE,它可以监视两个操作。使用 IN_MOVED_FROMIN_MOVED_TO 来测试事件类型。

最后,namelen 包含文件的名称(但不包括路径)和受影响文件的名称的长度。

构建示例应用程序代码

要构建这些代码,请将目录 /home/strike 更改到您的主目录,即将这些代码保存到一个文件中,然后调用 C 编译器 — 在大部分 Linux 系统中为 gcc。然后,运行这个可执行文件,如清单 3 所示。

清单 3. 运行可执行文件
% cc -o watcher watcher.c
% ./watcher

在监视程序运行时,打开第二个终端窗口并使用 touchcatrm 来更改主目录的内容,如清单 4 所示。完成之后,重新启动您的新应用程序。

清单 4. 使用 touch、cat 和 rm
% cd $HOME
% touch a b c
The file a was created.
The file b was created.
The file c was created.

% ./watcher &
% rm a b c
The file a was deleted.
The file b was deleted.
The file c was deleted.

% ./watcher &
% touch a b c
The file a was created.
The file b was created.
The file c was created.

% ./watcher &
% cat /etc/passwd >> a
The file a was modified.

% ./watcher &
% mkdir d
The directory d was created.

试用其他可用的监视标志。要捕捉权限的更改,请将 IN_ATTRIB 添加到 mask。

使用 inotify 的技巧

您还可以使用 select()pselect()poll()epoll() 来避免阻塞。如果您想将监视器的监控作为图形应用程序的主事件处理循环的一部分,或作为监视其他输入连接的守护进程的一部分,这是很有用的。将该 inotify 描述符添加到这组描述符中,进行并发监控。清单 5 展示了 select() 的标准形式。

清单 5. select() 的标准形式
int return_value;
fd_set descriptors;
struct timeval time_to_wait;

FD_ZERO ( &descriptors );
FD_SET( …, &descriptors );
FD_SET ( fd, &descriptors );

time_to_wait.tv_sec = 3;
time.to_waittv_usec = 0;

return_value = select ( fd + 1, &descriptors, NULL, NULL, &time_to_wait);

if ( return_value < 0 ) {
/* Error */
}

else if ( ! return_value ) {
/* Timeout */
}

else if ( FD_ISSET ( fd, &descriptors ) ) {
/* Process the inotify events */

}

else if …

select() 方法在 time_to_wait 期间暂停程序。然而,如果在这个延迟期间这组描述符的任意一个文件描述符发生活动,将立即恢复执行程序。否则,调用就会超时,允许应用程序执行其他进程,比如在图形用户界面(GUI)工具中响应鼠标或键盘事件。

下面是使用 inotify 的其他技巧:

  • 如果监视中的文件或目录被删除,它的监视器也会被自动删除(在删除事件发出之后)。
  • 如果在已卸载的文件系统上监控文件或目录,监视器将在删除所有受影响的监视之前收到一个卸载事件。
  • IN_ONESHOT 标志添加到监视器标记中,设置一个一次性警告。警告在发送之后将被删除。
  • 要修改一个事件,必须提供相同的路径名和不同的标记。新监视器将取代老监视器。
  • 考虑到实用性,不可能耗尽任何一个 inotify 实例的监视器。然而,您可能会耗尽事件队列的空间,这取决于处理事件的频率。队列溢出会引起 IN_Q_OVERFLOW 事件。
  • close() 方法毁坏 inotify 实例和所有相关联的监视器,并清空队列中的所有等待事件。



回页首

安装 inotify 工具套件

inotify 编程界面很容易使用,但如果您不想编写自己的工具,可以使用一种开源的灵活的代替方法。Inotify 工具库(参见下面的 参考资料 获得链接)提供一对监控文件系统活动的命令行实用程序:

  • inotifywait 仅执行阻塞,等待 inotify 事件。您可以监控任何一组文件和目录,或监控整个目录树(目录、子目录、子目录的子目录等等)。在 shell 脚本中使用 inotifywait
  • inotifywatch 收集关于被监视的文件系统的统计数据,包括每个 inotify 事件发生多少次。

在 撰写本文时,最新版本的 inotify 库是 version 3.13,于 2008 年 1 月发布。安装 inotify 工具有两种方法:可以下载并亲自构建该软件,或使用 Linux 发布版的包管理器安装一组二进制文件(如果已知库包含 inotify 工具)。要在基于 Debian 的发布版上使用后一种方法,请运行 apt-cache search inotify,并查找匹配的工具,如清单 6 所示。在本文的示例系统 Ubuntu Desktop version 8.04 上,这些工具已经可用。

清单 6. 搜索 inotify 工具
% apt-cache search inotify
incron – cron-like daemon which handles filesystem events
inotail – tail replacement using inotify
inoticoming – trigger actions when files hit an incoming directory
inotify-tools – command-line programs providing a simple interface to inotify
iwatch – realtime filesystem monitoring program using inotify
libinotify-ruby – Ruby interface to Linux’s inotify system
libinotify-ruby1.8 – Ruby interface to Linux’s inotify system
libinotify-ruby1.9 – Ruby interface to Linux’s inotify system
libinotifytools0 – utility wrapper around inotify
libinotifytools0-dev – Development library and header files for libinotifytools0
liblinux-inotify2-perl – scalable directory/file change notification
muine-plugin-inotify – INotify Plugin for the Muine music player
python-kaa-base – Base Kaa Framework for all Kaa Modules
python-pyinotify – Simple Linux inotify Python bindings
python-pyinotify-doc – Simple Linux inotify Python bindings
% sudo apt-get install inotify-tools

Setting up inotify-tools.

但是构建代码也是很容易的。下载并解压缩源文件;然后配置、编译和安装它,如清单 7 所示。整个过程可能需要 3 分钟。

清单 7. 构建代码
% wget
http://internap.dl.sourceforge.net/sourceforge/inotify-tools/inotify-tools-3.13.tar.gz
% tar zxvf inotify-tools-3.13.tar.gz
inotify-tools-3.13/
inotify-tools-3.13/missing
inotify-tools-3.13/src/
inotify-tools-3.13/src/Makefile.in

inotify-tools-3.13/ltmain.sh

% cd inotify-tools.3.13
% ./configure
% make
% make install

现在,您可以使用这个工具了。例如,如果您想监控整个主目录的更改,请运行 inotifywait。最简单的调用是 inotifywait -r -m,它循环监控参数(-r),并使该实用程序在每个事件(-m)之后保持运行:

% inotifywait -r -m $HOME
Watches established.

运行另一个终端窗口,并修改您的主目录。有趣的是,即使一个简单的通过 Is 列出的目录也生成一个事件:

/home/strike OPEN,ISDIR

阅读 inotifywait 手册页获得将事件限制到特定列表(反复地使用 -e event_name 选项来创建列表)的选项,并从循环的监视器中排除匹配的文件(--exclude pattern)。



回页首

继续使用 inotify

就像上面揭示的 apt-cache ,您还可以考虑使用许多其他基于 inotify 的实用程序。incron 实用程序源自于 cron,但它响应 inotify 事件,而不是调度。inoticoming 实用程序专门用于监控收存箱。如果您是 Perl、Ruby 或 Python 开发人员,您可以找到从您喜欢的脚本语言调用 inotify 的模块和库。

例如,Perl 编程人员可以使用 Linux::Inotify2(参见 参考资料 获得详细信息)来将 inotify 特性嵌入到任何 Perl 应用程序中。这些取自 Linux::Inotify2 README 文件的代码演示了监控事件的回调接口,如清单 8 所示。

清单 8. 监控事件的回调接口
use Linux::Inotify2;

my $inotify = new Linux::Inotify2
or die "Unable to create new inotify object: $!";

# for Event:
Event->io (fd =>$inotify->fileno, poll => ‘r’, cb => sub { $inotify->poll });

# for Glib:
add_watch Glib::IO $inotify->fileno, in => sub { $inotify->poll };

# manually:
1 while $inotify->poll;

# add watchers
$inotify->watch ("/etc/passwd", IN_ACCESS, sub {
my $e = shift;
my $name = $e->fullname;
print "$name was accessedn" if $e->IN_ACCESS;
print "$name is no longer mountedn" if $e->IN_UNMOUNT;
print "$name is gonen" if $e->IN_IGNORED;
print "events for $name have been lostn" if $e->IN_Q_OVERFLOW;

# cancel this watcher: remove no further events
$e->w->cancel;
});

因为 Linux 中的所有东西都是一个文件,所以您将发现 inotify 有大量的用法。

因此,问题可以归结为 “谁监视监视器?”

参考资料

学习

获得产品和技术

  • 下载 inotify 工具的源代码,这是一组监控文件系统的命令行实用程序。
  • 订购 SEK for Linux,共包含两张 DVD,其中有用于 Linux 的最新 IBM 试用软件,包括 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere®。
  • 使用可直接从 developerWorks 下载的 IBM 试用软件 构建您的下一个 Linux 开发项目。

讨论

关于作者

Martin Streicher 的照片

Martin Streicher 是一位自由 Web 开发人员,并且是 Linux Magazine 的前任主编。Martin 拥有 Purdue University 计算机科学的硕士学位,并从 1986 年开始编写 UNIX 风格的系统。他喜欢收藏艺术品和玩具。

inotify + rsync实现linux文件实时同步

公司一套系统的同步使用的donotify,不能实现子目录的实时同步,通过查资料,发现inotify可以实现子目录的实时同步,以下为笔记。
一、介绍Inotify 是文件系统事件监控机制,作为 dnotify 的有效替代。dnotify 是较早内核支持的文件监控机制。Inotify 是一种强大的、细粒度的、异步的机制,它满足各种各样的文件监控需要,不仅限于安全和性能。
inotify 可以监视的文件系统事件包括:IN_ACCESS,即文件被访问IN_MODIFY,文件被 writeIN_ATTRIB,文件属性被修改,如 chmod、chown、touch 等IN_CLOSE_WRITE,可写文件被 closeIN_CLOSE_NOWRITE,不可写文件被 closeIN_OPEN,文件被 openIN_MOVED_FROM,文件被移走,如 mvIN_MOVED_TO,文件被移来,如 mv、cpIN_CREATE,创建新文件IN_DELETE,文件被删除,如 rmIN_DELETE_SELF,自删除,即一个可执行文件在执行时删除自己IN_MOVE_SELF,自移动,即一个可执行文件在执行时移动自己IN_UNMOUNT,宿主文件系统被 umountIN_CLOSE,文件被关闭,等同于(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)IN_MOVE,文件被移动,等同于(IN_MOVED_FROM | IN_MOVED_TO)注:上面所说的文件也包括目录。

二、为能在shell下使用inotify特性,需要安装inotify-tools
1、inotify-tools:The general purpose of this package is to allow inotify’s features to be used from within shell scripts.
下载地址:http://inotify-tools.sourceforge.net/
编译安装./configuremakemake install完成后,注意查看manpage,man inotify 、 man inotifywait

  • inotifywait 仅执行阻塞,等待 inotify 事件。您可以监控任何一组文件和目录,或监控整个目录树(目录、子目录、子目录的子目录等等)。在 shell 脚本中使用 inotifywait
  • inotifywatch 收集关于被监视的文件系统的统计数据,包括每个 inotify 事件发生多少次。
  • 2、inotify的系统相关参数: /proc interfaces   The following interfaces can be used to limit the amount of kernel memory consumed by inotify:
       /proc/sys/fs/inotify/max_queued_events   The value in this file is used when an application calls inotify_init(2) to set an upper limit on the number of events that can be queued to the corresponding inotify instance. Events in excess of this limit are dropped, but an IN_Q_OVERFLOW event is always generated.
       /proc/sys/fs/inotify/max_user_instances   This specifies an upper limit the number of inotify instances that can be created per real user ID.
       /proc/sys/fs/inotify/max_user_watches   This specifies a limit the number of watches that can be associated with each inotify instance.

    3、inotifywait 相关的参数(更多,查看manpage):inotifywaitThis command simply blocks for inotify events, making it appropriate for use in shell scripts. It can watch any set of files and directories, and can recursively watch entire directory trees.-m, –monitor   Instead of exiting after receiving a single event, execute indefinitely. The default behaviour is to exit after the first event occurs.-r, –recursive   Watch all subdirectories of any directories passed as arguments. Watches will be set up recursively to an unlimited depth. Symbolic links are not
    traversed. Newly created subdirectories will also be watched.-q, –quiet   If specified ce, the program will be less verbose. Specifically, it will not state when it has completed establishing all inotify watches. -e <event>, –event <event>   Listen for specific event(s) ly. The events which can be listened for are listed in the EVENTS section. This option can be specified more than ce. If omitted, all events are listened for. use“,”separate multi events

    三、使用1.查看是否支持inotify,从kernel 2.6.13开始正式并入内核,RHEL5已经支持。看看是否有 /proc/sys/fs/inotify/目录,以确定内核是否支持inotify[root@RHEL5 Rsync]# ll /proc/sys/fs/inotifytotal 0-rw-r–r– 1 root root 0 Oct 9 09:36 max_queued_events-rw-r–r– 1 root root 0 Oct 9 09:36 max_user_instances-rw-r–r– 1 root root 0 Oct 9 09:36 max_user_watches
    2.关于递归:inotifywaitThis command simply blocks for inotify events, making it appropriate for use in shell scripts. It can watch any set of files and directories, and can recursively watch entire directory trees.

    3.使用:#!/bin/shsrc=/opt/webmaildes=/tmpip=192.168.7.192
    /usr/local/bin/inotifywait -mrq –timefmt ‘%d/%m/%y %H:%M’ –format ‘%T %w%f’ -e modify,delete,create,attrib ${src} | while read file   do   rsync -avz –delete –progress ${src} root@${ip}:${des} &&   echo "${file} was rsynced"   echo "—————————————————————————"   done注:当要排出同步某个目录时,为rsync添加–exculde=PATTERN参数,注意,路径是相对路径。详细查看man rsync当要排除都某个目录的事件监控的处理时,为inotifywait添加–exclude或–excludei参数。详细查看man inotifywait
    另:/usr/local/bin/inotifywait -mrq –timefmt ‘%d/%m/%y %H:%M’ –format ‘%T %w%f’ -e modify,delete,create,attrib ${src} 上面的命令返回的值类似于:10/03/09 15:31 /wwwpic/1这3个返回值做为参数传给read,关于此处,有人是这样写的:inotifywait -mrq -e create,move,delete,modify $SRC | while read D E F;do
    细化了返回值。

    说明: 当文件系统发现指定目录下有如上的条件的时候就触发相应的指令,是一种主动告之的而非我用循环比较目录下的文件的异动,该程序在运行时,更改目录内的文件时系统内核会发送一个信号,这个信号会触发运行rsync命令,这时会同步源目录和目标目录。–timefmt:指定输出时的输出格式   –format: ‘%T %w%f’指定输出的格式,上面的输出类似于:12/10/08 06:34 /opt/webmail/dovecot-1.1.2/src/test/1

    使用rsync+inotify配置触发式(实时)远程同步

    使用rsync+inotify配置触发式(实时)远程同步 2008-11-01 TsengYia#126.com ################################################################
    系统环境:RHEL5 [ 2.6.18-8.el5xen ]
    软件环境:
        rsync-2.6.8-3.1
        nfs-utils-1.0.9-16.el5
        portmap-4.0-65.2.2.1    inotify-tools-3.13.tar.gz
            —— http://downloads.sourceforge.net/inotify-tools/inotify-tools-3.13.tar.gz?modtime=1199213676&big_mirror=0 目标功能:
        源主机H1: 192.168.1.11/24
        目标主机H2: 192.168.1.12/24
       
        将H1主机中的开发数据(/var/devel/目录),上传同步至H2主机的/backup/devel/h1/目录。——当源数据有文件或目录更新时,即时启动rsync同步进程。[基于安全性考虑,建议只在内部网络中使用] ################################################################    除inotify-tools(需要2.6.13以上内核的inotify功能支持)以外,其他软件均使用RHEL5系统自带的rpm包安装。 一、配置目标主机H2(发布NFS可写共享)
       
    shell> mkdir -p /backup/devel/h1/shell> vi /etc/exports
    /backup/devel/h1    192.168.1.11(rw,no_root_squash)shell> service portmap start
    shell> service nfs startshell> chkconfig portmap
    shell> chkconfig nfs    如有必要,可以结合防火墙规则控制访问权限
    shell> iptables -I INPUT -p tcp –dport 111 -j DROP
    shell> iptables -I INPUT -p tcp –dport 111 -s 192.168.1.11 -j ACCEPT
    shell> iptables -I INPUT -p udp –dport 111 -j DROP
    shell> iptables -I INPUT -p udp –dport 111 -s 192.168.1.11 -j ACCEPT
    二、配置源主机H1(上传备份发起端)     1、安装inotify-tools工具包shell> tar zxvf inotify-tools-3.13.tar.gz -C /usr/src/
    shell> cd /usr/src/inotify-tools-3.13
    shell> ./configure
    shell> make
    shell> make install—— 可以使用man inotify、man inotifywait、man inotifywatch查看相关手册页。     2、挂载H2发布的备份目录shell> service portmap start
    shell> chkconfig portmapshell> mkdir -p /media/h2nfsdir/
    shell> vi /etc/fstab
    192.168.0.12:/backup/devel/h1    /media/h2nfsdir    nfs    defaults,noexec    0 0shell> mount /media/h2nfsdir     3、编写触发同步脚本shell> vi /opt/h1-h2_inosync.sh
    #!/bin/sh
    SRC=/var/devel/
    DST=/media/h2nfsdir/
    INWT=/usr/local/bin/inotifywait
    RSYNC=/usr/bin/rsync
    $INWT -mrq -e create,move,delete,modify $SRC | while read D E F ; do
        $RSYNC -aHqz –delete $SRC $DST
    doneshell> chkmod +x /opt/h1-h2_inosync.sh     4、每次开机自动运行监控脚本shell> echo "/opt/h1-h2_inosync.sh &" >> /etc/rc.local
    shell> /opt/h1-h2_inosync.sh &
    三、测试实时同步
        在源主机H1上,修改/var/devel/目录中的内容(如增、删、改文件,添加、移除目录等),
        ——同时在目标主机H2上,观察备份目录/backup/devel/h1/中内容的变化。 ############################## The End ##################################

    远程启动windows的远程桌面服务

    1. 以管理员身份登录到工作站

    2. 打开注册表编辑器

    3. 点击菜单 文件 ——〉连接网络注册表

    4. 在"选择计算机"的对话框中 输入远程计算机名 或者浏览活动目录定位远程服务器 或者点"高级"来查找远程计算机

    5. 点击"确定"后 注册表编辑器中将显示远程机器的两个注册表分支:即 HKEY_LOCAL_MACHINE (HKLM) 和 HKEY_USERS (HKU)

        6. 定位到远程机器的
    HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlTerminal Server
    节点 在右边找到 fDenyTSConnection 这样一个REG_DWORD 键 双击打开 将键值从1 (禁用远程桌面) 改为0 (启用远程桌面)

    7. 在 CMD 中输入以下命令 重启远程计算机(将hostname 替换为远程计算机名):

    shutdown -m hostname -r

    8. 远程计算机的远程桌面就已经启用了 并在默认端口(3389)进行监听 出于安全考虑 应该及时更改监听的端口 会的话 就不用往下看了 …

    9. 在注册表中定位到远程机器的 KEY_LOCAL_MACHINESystemCurrentControlSetControlTerminalServerWinStationsRDP-Tcp 节点下 选中"十进制"表示 将默认的端口值改为其他的 …

    在不停止mysql复制主服务器的情况下,配置一个mysql复制从服务器

    首先配置好从服务器的my.cnf,启动mysql。

    1.在主服务器上,备份数据库

    mysqldump -uroot -p111111 –master-data -B game ucenter uchome ihompy > ihompy.sql

    备份数据库,注意必需带–master-data参数。

    2.在从服务器上的mysql内:

    stop slave
    停止从服务器的数据更新。

    3.导入备份数据库到从服务器内:

    mysql -h 10.11.12.26 -uroot -p111111 < ihompy.sql

    4.看导入是否成功

    比对show slave status和head -n 50 ihompy.sql内的MASTER_LOG_FILE及MASTER_LOG_POS是否相同。相同说明导入OK。

    5.启动从服务器:

    start slave

    再用show slave status看看是否有报错,MASTER_LOG_POS是否有变化,无报错,有变化说明配置成功了。