GNU Wget 1.10.2,非交互式的网络文件下载工具。
用法: wget [选项]... [URL]...
Mandatory arguments to long options are mandatory for short options too.
开始:
-V, --version 显示Wget版本之后退出。
-h, --help 显示本帮助
-b, --background 启动后转到后台运行。
-e, --execute=COMMAND 运行 `.wgetrc'-那样的命令。
日志和输入文件:
-o, --output-file=FILE 将日志记录到文件 FILE.
-a, --append-output=FILE 添加消息到文件 FILE.
-d, --debug 输出大量调试信息。
-q, --quiet 静默模式 (无输出)。
-v, --verbose 显示信息 (默认打开).
-nv, --no-verbose 显示很少信息但不是完全安静.
-i, --input-file=FILE 下载存储在 FILE 文件中的所有URL地址指向的文件。
-F, --force-html 把输入文件当成 HTML.
-B, --base=URL prepends URL to relative links in -F -i file.
下载:
-t, --tries=NUMBER 设定重试次数(0 一直重试)。
--retry-connrefused retry even if connection is refused.
-O, --output-document=FILE 写入文档到 FILE.
-nc, --no-clobber 跳过将要到已存在文件的下载。
-c, --continue 续传下载。
--progress=TYPE select progress gauge type.
-N, --timestamping don't re-retrieve files unless newer than
local.
-S, --server-response 显示服务器的响应。
--spider 什么都不下载
-T, --timeout=SECONDS 把所有超时时间设为SECONDS秒。
--dns-timeout=SECS 把DNS超时时间设为SECS秒。
--connect-timeout=SECS 设定连接超时为 SECS.
--read-timeout=SECS 设定读取超时为 SECS.
-w, --wait=SECONDS wait SECONDS between retrievals.
--waitretry=SECONDS wait 1..SECONDS between retries of a retrieval.
--random-wait wait from 0...2*WAIT secs between retrievals.
-Y, --proxy 显示打开代理
--no-proxy 显示关闭代理
-Q, --quota=NUMBER set retrieval quota to NUMBER.
--bind-address=ADDRESS bind to ADDRESS (hostname or IP) on local host.
--limit-rate=RATE 把下载速度限制为RATE。
--no-dns-cache 禁止查找DNS缓存。
--restrict-file-names=OS restrict chars in file names to ones OS allows.
-4, --inet4-only 仅连接IPv4地址。
-6, --inet6-only 只连接到 IPv6 地址。
--prefer-family=FAMILY connect first to addresses of specified family,
one of IPv6, IPv4, or none.
--user=USER 把ftp和http的用户名设定为UESR。
--password=PASS 把ftp和http的密码设定为PASS。
目录:
-nd,--no-directories 不建立文件夹。
-x,--force-directories 强制建立文件夹。
-nH, --no-host-directories 不创建主机目录。
--protocol-directories use protocol name in directories.
-P, --directory-prefix=PREFIX 将文件保存到 PREFIX/...
--cut-dirs=NUMBER ignore NUMBER remote directory components.
HTTP 选项:
--http-user=USER 将 http用户设为 USER.
--http-password=PASS 将http密码设为 PASS.
--no-cache 不接受服务器缓存的数据.
-E,--html-extension 以'.html'扩展名保存HTML文档。
--ignore-length ignore `Content-Length' header field.
--header=STRING insert STRING among the headers.
--proxy-user=USER 设定 USER 作为代理用户名。
--proxy-password=PASS 设定 PASS 作为代理密码。
--referer=URL include `Referer: URL' header in HTTP request.
--save-headers 保存 HTTP 头到文件。
-U, --user-agent=AGENT identify as AGENT instead of Wget/VERSION.
--no-http-keep-alive disable HTTP keep-alive (persistent connections).
--no-cookies 不使用cookies.
--load-cookies=FILE 在会话前从文件中读取cookies。
--save-cookies=FILE 在会话结束后保存 cookies 到 FILE。
--keep-session-cookies load and save session (non-permanent) cookies.
--post-data=STRING use the POST method; send STRING as the data.
--post-file=FILE use the POST method; send contents of FILE.
HTTPS (SSL/TLS) 选项:
--secure-protocol=PR choose secure protocol, one of auto, SSLv2,
SSLv3, and TLSv1.
--no-check-certificate don't validate the server's certificate.
--certificate=FILE client certificate file.
--certificate-type=TYPE client certificate type, PEM or DER.
--private-key=FILE private key file.
--private-key-type=TYPE private key type, PEM or DER.
--ca-certificate=FILE file with the bundle of CA's.
--ca-directory=DIR directory where hash list of CA's is stored.
--random-file=FILE file with random data for seeding the SSL PRNG.
--egd-file=FILE file naming the EGD socket with random data.
FTP 选项:
--ftp-user=USER 设置ftp用户为 USER.
--ftp-password=PASS 设置ftp密码为 PASS.
--no-remove-listing don't remove `.listing' files.
--no-glob turn off FTP file name globbing.
--no-passive-ftp disable the "passive" transfer mode.
--retr-symlinks when recursing, get linked-to files (not dir).
--preserve-permissions preserve remote file permissions.
递归下载:
-r, --recursive specify recursive download.
-l, --level=NUMBER maximum recursion depth (inf or 0 for infinite).
--delete-after delete files locally after downloading them.
-k, --convert-links make links in downloaded HTML point to local files.
-K, --backup-converted before converting file X, back up as X.orig.
-m, --mirror shortcut for -N -r -l inf --no-remove-listing.
-p, --page-requisites get all images, etc. needed to display HTML page.
--strict-comments turn on strict (SGML) handling of HTML comments.
Recursive accept/reject:
-A, --accept=LIST comma-separated list of accepted extensions.
-R, --reject=LIST comma-separated list of rejected extensions.
-D, --domains=LIST comma-separated list of accepted domains.
--exclude-domains=LIST 被拒绝的域名的用逗号分开的列表。
--follow-ftp follow FTP links from HTML documents.
--follow-tags=LIST comma-separated list of followed HTML tags.
--ignore-tags=LIST comma-separated list of ignored HTML tags.
-H, --span-hosts 当递归时转到陌生的主机。
-L, --relative 只跟随相对链接。
-I, --include-directories=LIST 允许的目录的列表。
-X, --exclude-directories=LIST 不包括的目录的列表。
-np, --no-parent don't ascend to the parent directory.
日志统计分析软件Awstats需要Perl支持,但是Nginx内建的Perl模块目前还并不稳定,经常会出问题,所以还是用FastCGI模式运行Perl比较可靠。下面就谈谈如何在Nginx下配置Perl的FastCGI模式: 首先,安装Perl的FastCGI模块: #wget http://www.cpan.org/modules/by-module/FCGI/FCGI-0.67.tar.gz 其实也可以用这种方法:#perl -MCPAN -e ‘install FCGI’ #!/usr/bin/perl close(PARENT_WR); } 将权限改为可执行,并执行之。 配置nginx.conf,使之支持perl脚本: location ~* .*\.pl$ 编辑awstats.conf fastcgi_pass unix:/tmp/perl_fastcgi.sock; 然后重启nginx:
#tar zxvf FCGI-0.67.tar.gz
#cd FCGI-0.67
# perl Makefile.PL
#make && make install
然后,配置Perl的FastCGI脚本(从网上找到的,未找到原始出处):
use FCGI;
use Socket;
use POSIX qw(setsid);
require ’syscall.ph’;
&daemonize;
END() { } BEGIN() { }
*CORE::GLOBAL::exit = sub { die “fakeexit\nrc=”.shift().”\n”; };
eval q{exit};
if ($@) {
exit unless $@ =~ /^fakeexit/;
};
&main;
sub daemonize() {
chdir ‘/’ or die “Can’t chdir to /: $!”;
defined(my $pid = fork) or die “Can’t fork: $!”;
exit if $pid;
setsid or die “Can’t start a new session: $!”;
umask 0;
}
sub main {
$socket = FCGI::OpenSocket( “/tmp/perl_fastcgi.sock”, 10 );
$request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%req_params, $socket );
if ($request) { request_loop()};
FCGI::CloseSocket( $socket );
}
sub request_loop {
while( $request->Accept() >= 0 ) {
$stdin_passthrough =”;
$req_len = 0 + $req_params{’CONTENT_LENGTH’};
if (($req_params{’REQUEST_METHOD’} eq ‘POST’) && ($req_len != 0) ){
my $bytes_read = 0;
while ($bytes_read < $req_len) {
my $data = '';
my $bytes = read(STDIN, $data, ($req_len - $bytes_read));
last if ($bytes == 0 || !defined($bytes));
$stdin_passthrough .= $data;
$bytes_read += $bytes;
}
}
if ( (-x $req_params{SCRIPT_FILENAME}) &&
(-s $req_params{SCRIPT_FILENAME}) &&
(-r $req_params{SCRIPT_FILENAME})
){
pipe(CHILD_RD, PARENT_WR);
my $pid = open(KID_TO_READ, "-|");
unless(defined($pid)) {
print("Content-type: text/plain\r\n\r\n");
print "Error: CGI app returned no output - Executing $req_params{SCRIPT_FILENAME} failed !\n";
next;
}
if ($pid > 0) {
close(CHILD_RD);
print PARENT_WR $stdin_passthrough;
close(PARENT_WR);
while(my $s = ) { print $s; }
close KID_TO_READ;
waitpid($pid, 0);
} else {
foreach $key ( keys %req_params){
$ENV{$key} = $req_params{$key};
}
if ($req_params{SCRIPT_FILENAME} =~ /^(.*)\/[^\/]+$/) {
chdir $1;
}
close(STDIN);
syscall(&SYS_dup2, fileno(CHILD_RD), 0);
exec($req_params{SCRIPT_FILENAME});
die(”exec failed”);
}
}
else {
print(”Content-type: text/plain\r\n\r\n”);
print “Error: No such CGI app - $req_params{SCRIPT_FILENAME} may not exist or is not executable by this process.\n”;
}
}
{
include awstats.conf;
}
fastcgi_index awstats.pl;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
fastcgi_read_timeout 60;
#service nginx restart
What Is POE, And Why Should I Use It?
回顾一下我们每天写的程序,可以发现这些程序大部分都有着基本的结构:启动,执行一系列的动作,然后退出。对于那些在用户和他们的数据之间不需要很多交互的应用中,这样的程序都能工作得很好。然后,如果是如果是碰到了复杂的任务,我想你就需要一个更加好的程序框架理解任务的复杂性,完成这个任务。
所以POE(Perl 对象环境)应运而生了。POE是一个构建Perl程序的框架,以更自然地完成那些需要对外部数据作出反应的任务,比如网络通讯或者用户接口。用POE写的程序完全是非线性的;你只需要建立一些小的子程序,并且定义好它们之间如何相互调用,那么POE就会根据程序处理的输入输出,自动在它们之间切换。说到现在,你可能已经头晕了。如果你习惯于看代码去理解,那么看了下面一个小例子后,你就会恍然大悟了。
POE Design
说POE是一个小的操作系统一点都不夸张,它有它自己的内核,进程,进程间通讯(IPC),驱动等等这些。实际上,它是一个简单的系统,构建了一系列的状态信息。下面对组成POE各个部分的一个简单的描述:
States
POE的基本程序块就是状态,它是一些代码,当事件发生时触发执行。例如,输入的数据到达,一个会话过期,一个会话传递了一条信息给另一个会话。POE里的每件事情都是基于接收和处理各种各样的事件。
The Kernel
POE的内核跟操作系统的内核很象:它守护着后台的所有你的进程和数据,安排你的代码的触发。你能够用POE的内核来为你的进程设置警报,控制你的状态队列和其他一些低级服务,当然,大部分时间你不用直接来跟内核交互。
Sessions
POE里的会话相当于一个真的操作系统里的进程。一个会话就是一个POE程序,当它在运行时不停地在状态之间切换。它能够创建子会话,传递信息给其他的会话等等。每个会话都能通过调用 heap 存储会话特有的数据,这些数据在会话中的各个状态都是可以存取的。
POE有一个简单的协作的多任务处理模块;每个会话在同一个OS进程中执行,不需要任何线程和进程。对于这样的会话,你应该特别注意在POE程序中使用模块化的系统调用。
这些就是POE的最基本的部分,但是在我们开始实际的代码前还需要稍微ie解释一些高级的POE的部分。
Drivers
驱动位于POE最低级的I/O层。目前,只有一个驱动包括在POE的安装中-- POE::Driver::SysRW,它读写文件句柄中的数据。不管怎样,我们都不需要直接使用驱动。
Filters
过滤器,在某个方面来说,是非常有用的。过滤器是一个简单的接口,转换数据块从一个格式成另一个格式。例如,POE::Filter::HTTPD 能够在 HTTP 1.0 requests 之间 HTTP::Request 对象互相转换。POE::Filter::Line 能够见数据流转换成序列化数据行。
Wheels
Wheels包含了每天任务的可重复利用的高级逻辑部分。它们是POE封装有用代码的方法。在POE中你需要处理到的Wheels包括事件驱动的输入输出数据和网络连接的创建。Wheels经常使用过滤器和驱动来处理和传递数据。这个描述太过于含糊了,下面的代码将会给出一个例子来说明这个概念。
Components
组件是一个会话,被设计来受控于其它会话。你的会话能够从它们那里来处理命令和接受事件,这点很象真实操作系统中的通过IPC通讯。一个组件的例子就是POE::Component::IRC,一个创建基于POE的IPC客户端接口,或者是POE::Component::Client::HTTP,一个事件驱动的Perl实现的HTTP用户代理。组件同样是POE非常有用的一个部分。
A Simple Example
在这个例子中,我们会建立一个守护进程服务端,它接受TCP连接,同时打印由它的客户端提交的算术问题的答案。当有人连接它的端口31008,它将打印“Hello,client”。客户端能够提交一个算术表达式,以一个新行结束提交,服务端将送回表达式的答案。够简单吧。
写这样一个POE程序跟写一个Unix下的守护进程的传统方法没有什么很大的不同。我们将有一个服务器会话在端口31008监听TCP连接。每当连接到来时,它将创建一个子会话来处理连接。每个子会话都能跟用户交互,然后在连接断开后安静地死掉。所有这些用Perl简单地实现只需要模块化的72行代码就行了。
这个程序简单地以下面的代码开始:
1 #!/usr/bin/perl -w
2 use strict;
3 use Socket qw(inet_ntoa);
4 use POE qw( Wheel::SocketFactory Wheel::ReadWrite
5 Filter::Line Driver::SysRW );
6 use constant PORT => 31008;
这一段我们导入了脚本所需要的模块以及函数,并定义了监听端口的常量值。”use POE;”后面的 qw()语句一次导入了很多POE::模块。
现在开始本文最酷的部分:
7 new POE::Session (
8 _start => \&server_start,
9 _stop => \&server_stop,
10 );
11 $poe_kernel->run();
12 exit;
这样就已经是一个完整的程序了!我建立了服务端会话,告诉POE内核开始执行事件,并且在事件结束后退出。(当没有任何会话需要管理的时候,POE内核就认为事情做完了,但是既然我们已经打算把服务端会话放在一个无穷的循环中,它将不会以这种发式退出)POE在你写"use POE;"h后,自动输出变量$poe_kernel 到你的名字空间中。
new POE::Session 方法调用需要解释一下。当你创建一个会话时,你给内核一个这个会话将接受事件的列表。在上面的代码中,意味着这个新的会话将通过调用&server_start,&server_stop处理_start和_stop事件。任何一个受到的但没有列举到的事件,将会被会话忽略。_Start和_Stop事件对于一个POE会话来说是一个特殊事件。_start事件是当一个会话创建时第一件要做的事情,当会话将要被摧毁时内核就通知这个会话进入_stop状态。
现在,我们已经写了完整的程序,我们还要写当会话运行时要执行的状态代码。接下来,让我们以&server_start开始。当主要的服务端会话被创建,开始执行程序时,它将会被调用。
13 sub server_start {
14 $_[HEAP]->{listener} = new POE::Wheel::SocketFactory
15 ( BindPort => PORT,
16 Reuse => 'yes',
17 SuccessState => \&accept_new_client,
18 FailureState => \&accept_failed
19 );
20 print "SERVER: Started listening on port ", PORT, ".\n";
21 }
这是一个有关POE状态的很好的例子。首先:看到变量$_[HEAP]了吗?POE有一个特殊的方法来传递参数。@_数组是由许多外部的参数打包在一起的。外部参数包括目前内核,会话和状态名的一个引用,堆栈的引用,以及其它一些东西。我们可以用POE导出的特殊常量来作为这个数组索引,比如 HEAP, SESSION, KERNEL, STATE和ARG0~ARG9(用户提供的参数)。跟POE的大部分设计一样,这样子的安排能够最大化后面的兼容性而又不牺牲速度。上面的例子存储了一个 SocketFactory wheel 在键值 listen 下。
POE::Wheel::SocketFactory wheel是POE里最酷的东西之一。你能够用它创建任何一个流socket(UDP socket还不行),而不需要担心细节。上面的代码将创建一个SocketFactory来监听特殊的TCP端口的新连接。当连接建立时,它将调用&accept_new_client来传递一个新的客户端,如果在这其中发生错误了,它将调用&accept_failed,而不是让我们自己来处理错误。这差不多就是用POE在网络中要做的。
我们存储一个wheel在堆栈中,以防止在状态的最后被Perl的垃圾收集机制意外地消灭掉,——这个方法在会话的每个状态中到处存在。现在我们来看&server_stop 状态的代码: 22 sub server_stop {
23 print "SERVER: Stopped.\n";
24 }
这段不需要多解释了。接下来的是我们创建一个新的会话来处理每个新到的连接。 25 sub accept_new_client {
26 my ($socket, $peeraddr, $peerport) = @_[ARG0 .. ARG2];
27 $peeraddr = inet_ntoa($peeraddr);
28 new POE::Session (
29 _start => \&child_start,
30 _stop => \&child_stop,
31 main => [ 'child_input', 'child_done', 'child_error' ],
32 [ $socket, $peeraddr, $peerport ]
33 );
34 print "SERVER: Got connection from $peeraddr:$peerport.\n";
35 }
当客户端成功地建立了跟服务端的连接后,我们的 POE::Wheel::SocketFactory将调用这个子例程。
我们将socket地址转换成人可读的IP地址,并且建立一个新的会话来跟客户端通讯。这跟前面的
POE::Session 构造器很象,但是有几点在接下来要说明。
@_[ARG0 .. ARG2]是($_[ARG0], $_[ARG1], $_[ARG2])的快捷方式。你会在POE程序中
看到很多这样的数组切片。
看31行:好像有点奇怪,其实这是一种很聪明的缩写。它可以用下面的比较长的方法来重写:
new POE::Session (
...
child_input => &main::child_input,
child_done => &main::child_done,
child_error => &main::child_error,
...
);
这是一个方便的做法来写出很多的状态名字,这些名字跟事件的名字是一样的。——你可以传递包名或者
对象来作为键,或者是任何一个有子例程,方法名组成的数组引用。可以参考POE::Session得到更多的信息。
最后,在POE::Session 构造器参数列表最后的数组引用是我们要手动传递给_start状态的参数列表。
如果POE::Wheel::SocketFactory在创建监听端口或者接受连接时产生了问题,下面的会发生:
36 sub accept_failed {
37 my ($function, $error) = @_[ARG0, ARG2];
38 delete $_[HEAP]->{listener};
39 print "SERVER: call to $function() failed: $error.\n";
40 }
打印错误信息是正常的处理方式,但是我们为什么还要从堆栈中删除SocketFactory wheel呢?答案在于
POE管理会话资源的方式。只要会话还能产生和接受事件,那么它就被认为是活动的。如果没有wheel,POE内核
会认为会话已经死了,并收集会话的资源。服务端得到事件的唯一方式就是从SocketFactory wheel,如果
它被消灭了,POE内核会一直等待,直到所有它的子会话结束,再收集所有占用的资源。在这一点上,既然
已经没有剩下的会话需要执行,POE内核将会结束并退出。
所以,基本上来说,这是最通常的结束POE会话的方法:结束所有会话资源,让内核干剩下的工作。现在,
我们谈到子会话的细节。
41 sub child_start {
42 my ($heap, $socket) = @_[HEAP, ARG0];
43 $heap->{readwrite} = new POE::Wheel::ReadWrite
44 ( Handle => $socket,
45 Driver => new POE::Driver::SysRW (),
46 Filter => new POE::Filter::Line (),
47 InputState => 'child_input',
48 ErrorState => 'child_error',
49 );
50 $heap->{readwrite}->put( "Hello, client!" );
51 $heap->{peername} = join ':', @_[ARG1, ARG2];
52 print "CHILD: Connected to $heap->{peername}.\n";
53 }
每当新的子会话被创建来处理最新的连接客户端时上面的代码就会被调用。这里我们要介绍一种新的
POE wheel:ReadWrite wheel,这是一个由事件驱动的处理I/O任务的wheel。我们把它传递给文件
句柄,一个驱动,一个过滤器等等。接着,每当新的数据到达文件句柄时,wheel将发送一个child_input
事件给会话,如果有任何错误发生就会发送一个child_error 事件。
我们理解用这个新的wheel来输出字符串”Hello,client”给socket。最后,我们存储在堆栈中
的客户端地址和端口,并打印成功信息。
我们省略了 child_stop 的状态讨论。它只有一行长度。现在我们直接看主要的child_input 程序。 57 sub child_input {
58 my $data = $_[ARG0];
59 $data =~ tr{0-9+*/()-}{}cd;
60 return unless length $data;
61 my $result = eval $data;
62 chomp $@;
63 $_[HEAP]->{readwrite}->put( $@ || $result );
64 print "CHILD: Got input from peer: \"$data\" = $result.\n";
65 }
当客户端发送给我们一行数据,我们取得里面简单的算术表达式并eval它,然后把结果或者错误信息
发送给客户端。通常情况下,将客户端发送来的不可信任的数据直接就eval是非常危险的,所以我们要确保
在eval前,将字符串中所有的非数学字符全部过滤掉。子会话将一直保持接受数据直到客户端断开。
所有事件驱动的应用都是使用POE的好地方。
源代码:http://www.perl.com/2001/01/poe-math3.pl
前面对mogileFS做了一下简单介绍,这儿开始对他进行剖析。
首先剖析他用来做文件西信息track的表结构。
使用到的数据表
服务器的一些配置信息,采用key=>value的记录方式保存。
域定义
主机定义,主机的ip,存储节点服务所开的端口等信息。
主机上的可用设备定义,包括设备可用空间,使用的权重等信息,由存储服务定时更新设备的情况。
文件分类定义
记录文件的基本信息,属于什么类别,他的key和文件大小等信息
复制的临时文件信息?
记录要做删除的文件
要延迟删除的文件
记录什么设备上有什么文件,一个文件在不同设备上的存储各有一条记录。
损坏的文件,哪一个文件在什么设备上损坏了。
要做分发的文件,记录来源设备,失败次数和下次重试的时间等信息。
文件检查日志
不可到达的文件列表
mogileFS是一个依赖数据库做数据信息交换的系统,为了减少DB的操作次数,使用了memcached做一些查询结果的缓冲。
CONTINUE原文地址: mogileFS HighLevel Overview
下面简要阐述 MogileFS 是怎么工作的.
mogileFS由如下一些部分构成:
High-level 流程:
MogileFS是一套高效的文件自动备份组件,由Six Apart开发,广泛应用在包括LiveJournal等web2.0站点上。
MogileFS由3个部分组成:
第1个部分是server端,包括mogilefsd和mogstored两个程序。前者即是mogilefsd的tracker,它将一些全局信息保存 在数据库里,例如站点domain,class,host等。后者即是存储节点(store node),它其实是个HTTP Daemon,默认侦听在7500端口,接受客户端的文件备份请求。在安装完后,要运行mogadm工具将所有的store node注册到mogilefsd的数据库里,mogilefsd会对这些节点进行管理和监控。
第2个部分是utils(工具集),主要是MogileFS的一些管理工具,例如mogadm等。
第3个部分是客户端API,目前只有Perl API(MogileFS.pm),用这个模块可以编写客户端程序,实现文件的备份管理功能。☆
提供MogileFS.pm
这个天文数字的增长自有它的理由。跑步机变得噪音越来越小,并且使用简单。电脑控制的反馈功能包括心率、热量消耗、速度、速率,还有坡度。许多型号的产品设有预定的运动模式,甚至还有根据练习者的心率变化而自动改变速度与坡度的功能。当然,跑步机受到宠爱的最主要原因还是它在改善体能方面的高效率。
科学研究证 明,跑步机比其他任何有氧运动器械消耗的热量更多。一项在美国威斯康星州医学院进行的研究对跑步机、台阶机、固定自行车、越野滑雪机与划船机的效果进行了 比较。参与者以不同运动强度在不同器械上运动,结果发现,在高强度情况下跑步机是绝对的赢家,1小时能消耗850千卡热量,台阶机与划船趴列第二,第小时 700千卡。在低强度运动时,跑步机仍然是冠军,每小时消耗550千卡,而台阶机的消耗量是500千卡。
跑步机在提高耐力、消耗热量及减少体脂方面效果最为出色。但这些还不是它的惟一用途。跑步机对下肢和上肢的塑形都有很大帮助。以下介绍如何有效地使用跑步机以达到上述目的,重点集中在消耗体脂与热量方面。
1、减脂运动区
如何充分利用跑步机来达到健身减肥的 目的呢?减肥实际上就是一个热量消耗大于热量摄入的公式。如果你能实现负平衡,体脂就会减少。你一定听说过“减脂运动区”的说法,也就是说在最高心率的 65-70%进行有氧运动是最合适的减肥运动强度。这个理论的根据十分简单,在中、低强度运动时,身体能够向工作肌肉提供足够的氧气来进行有氧能量代谢, 而且肌肉在此条件下也能够最大化地利用贮存脂肪作 为热量来源消耗在运动过程中。相反,在高强度运动时,身体不能及时向工作肌肉提供足够的氧气来支持其代谢过程,于是热量在缺氧状态下被分解利用。这时消耗 的主要是碳水化合物,脂肪只占很小一部分。当然,在任何情况下,身体都不会单纯消耗脂肪或碳水化合物,从有氧代谢到无氧代谢有一个转化的过程。因此,如果 你的运动目的是消耗脂肪,这个“减脂运动区”似乎是很有道理的。
但是,如果我们进一步探究热量消耗的问题时会发现,虽然在低强度运动时消耗的脂肪比例较高,但是热量消耗的来源并不对长期减肥的效果产生重要影 响。记住,减肥是一个热量摄入与消耗的平衡问题。低强度运动时消耗的脂肪比例虽然较高,但是高强度运动所消耗的实际脂肪量可能更高,因为总消耗热量被提高 了。
因此,你应该把尽可能地增加单次运动的热量消耗放在第一位,这是实现持续的体内热量负平衡的关键。一项研究比较了两组18~34岁女性的减肥效果。其中一组人用高强度运动,另一组用低强度,两组人的饮食相同。11个星期后,高强度运动组显示出明显的体脂水平下降,而低强度组则没有发生体脂的变化。
高强度运动除了能消耗更多的热量以外,它对身体代谢率的提高效果在运动结束后还会持续一段时间,从而进一步促进了减脂效果。
2、减脂运动方法
由于高强度有氧运动是减肥与防止反弹的最佳方式,那么是否应该在运动中尽可能长时间地保持高强度呢?遗憾的是,虽然那样做可能在单位时间中最大程度地消耗了热量与脂肪,但是身体不可能坚持足够长的时间。因此把短时间的高强度运动与低强度的恢复交替进行是最可行的办法。
如何知道自己的运动强度呢?有两个常用的方法来确认运动强度。第一是用心率来衡量,第二是用“自我评定强度等级”(RPE)来判断。心率测定需 要佩戴一个心率监测器,然后用“220-年龄”的公式预算出你的目标心率。比如,一个35岁的人想采用65%的强度运动,那么计算方法就是(220- 35)×0.65=120。
虽然这个方法被广泛应用,但它有许多缺陷。最大的问题是“220-年龄”得出的最高心率不精确,每个人的实际最高心率会因为体质不同,而高于或 低于这个计算结果。除此以外,运动当天的身体状况,甚至天气,都会影响到心率。相比之下,RPE应该更实用与准确一些。RPE把运动强度分成1~20个不 同等级,1是不做任何努力,20是极度努力。在运动中你根据自己的感觉来做出判断。我们把在跑步机上锻炼的强度简单地分成以下3个档次:
一级——RPE 12~13,较容易,相当于65%心率,
二级——RPE 15~16,有难度,相当于80%心率。
三级——RPE 17~18,非常难,相当于90%心率。
当你在“一级”强度跑步时,应该可以边运动边清楚地说话,但不能唱歌。在“二级”强度时说话有些费力,但努力程度不能太高。你应该能够坚持运动20分钟以上。“三级”强度接近极度努力,只能坚持5~10分钟。
“一级”运动的目的是增强耐力,从高强度运动中恢复体力。“二级”运动,的一个重要目的是提高“乳酸耐受界”。肌肉在此强度下运动时,会在消耗 热量的同时产生许多副产品——乳酸。乳酸经过一系列化学反应可以再次转化为热量供肌肉使用,但是当乳酸的产生速度超过了转化速度而出现堆积,肌肉会迅速疲劳, 被迫降低运动强度直到停止。“二级”强度运动能够提高人体处理乳酸的能力,使你得以保持更长时间的高强度运动.“乳酸耐受界”提高后,曾令人感觉非常吃力 的运动强度会变得比较容易坚持了,你也会消耗掉更多热量与脂肪,“三级”运动强度也能促进这个过程,并改善下肢肌肉,包括臀肌、股二头肌与小腿肌的外形。
跑步机对减肥是种非常理想的运动器械,你能够准确地把握速度,坡度及时间,不管你是一个新手还是资深运动员,都能够根据自己的运动目的特别设计一套锻炼计划。以下是一个把三种运动强度结合在一起,以减肥为目标的周计划。
第一天:小运动量低强度
把跑步机坡度调到1%,强度“一级”,慢跑或快走40~60分钟。你不可能每天都进行高强度锻炼,肌肉需要调整恢复,以便更好地完成任务。
第二天:变速练习
把坡度上升到1%,跑或快走30~60分钟。每5分钟换一次强度,“一级”与“三级”交替进行。随着体能的加强,“三级”的时间也应该相应加长。这意味着持续提高身体的消耗热量能力。
第三天:休息或放松练习
你可以完全休息或练习第一天的内容。
第四天:“乳酸耐受界”练习
把跑步机坡度上升到1%,热身后以“二级”强度跑或快走20分钟。开始阶段你也许只能完成一次20分钟练习,随着体能增强,你会完成2次甚至3次20分钟的强度练习。两次之间慢跑5分钟恢复。
第五天:休息或放松练习(同第一天)
第六天:坡度练习
把跑步机坡度定在4%,用“二级”强度跑或快走1分钟。然后把坡度下降到2%,用“一级”强度跑或快走1分钟。再次提高坡度到5%,用“二级” 强度跑或走5分钟,之后下降到2%,放松1分钟。这样循环直到你达到坡度10%,最后以坡度2%放松5分钟结束。当你的体能得到提高.需要增加强度时,用 加快速度而不是坡度来实现。这个练习对加强下肢力量非常有效.也能改善下肢肌肉的线条。
第七天:休息
无论你的有氧健身目标是什么,使用跑步机都会有所帮助.合理利用这种绝妙的健身工具,你一定能够达到自己的目的。
减少患心脏病的危险
高强度运动不但能提高脂肪消耗能量与体能水平,而且还会降低患心脏病的危险。日本的一项有关长寿的研究证实,高强度的跑步比低强度的步行更能减少患冠心病的危险。
计算热量消耗
大多数跑步机都能显示热量消耗,但是这个数字通常不够准确。以下是一个简便的计算方法。如果你在“一级”强度运动,每分钟大约消耗3~5千卡热 量。中等强度每分钟消耗10千卡,而高强度则消耗15千卡热量。当然,锻炼者的体重因素也应该考虑在内。体重越大,消耗量越多。
CONTINUE很多人都选择跑步机来锻炼,可是你认真考虑过为什么要选择跑步机锻炼吗?请认真地阅读这份跑步机的“说明书”!
一般情况下,人们选择跑步机主要有几个目的,减肥、提高心肺功能、放松、康复等,但是每种目的在跑步机上都有不同的体现。
减肥:时间30~40分钟
因为消耗体内脂肪要在中等强度运动半小时到四十五分钟后才开始,所以,利用跑步机减肥一定要控制好时间和速度。最好将时间设定为30~40分钟,如 果还要进行其他运动,可以减少时间但最好不要低于20分钟,而速度的设定因性别不同存在差异,男的最好在6.5~8.5之间,而女的则最好在 5.5~7.5之间。而且要注意跑步时手臂的摆动,不要扶在扶手上,因为这样可以消耗更多的能量,也更自然安全。
练心肺:速度5~9坡度0%~10%
如果决定要练习自己的心脏,那么最好先去咨询一下运动医学专家。根据他的建议为自己设定目标心率,一般来说,当你在跑步时达到目标心率后,要维持 25~35分钟,而速度最好设定在5~9之间,坡度控制在0%~10%之间。当你完成整个运动后不要急着下来,最好把速度降下来再跑5分钟左后,做好恢复 工作。
热身:时间5~10分钟速度别超过8
如果你想利用跑步机进行热身或放松,时间控制在5~10分钟即可,而速度也最好不要超过8,尤其是在进行准备活动的时候最好循序先用4.5~6的速 度跑 3~5分钟,接着用8~10的速度跑2~3分钟,再降到5~7的速度跑3~5分钟。这样可以避免体力的不必要消耗。坡度用0%~4%就可以。
CONTINUEPERL灵活的进程函数是为了复制进程用于分担任务与程序的工作量。
PERL中复制进程有两种方法:fork()、system()与exec()。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
fork()部分:*NIX传统的复制进程方法
==============================================================
fork()函数:
作用:进程复制函数。
用法:$pid=fork();
讲解:
无参数;当本进程为父进程时返回值为子进程的PID值,当进程为子进程时返回值为0。
实例:
#!usr/bin/perl -w
$pid=fork(); #复制进程,并把返回值附入$pid
die "Error:$!\n" unless defined $pid; #制定程序的错误机制,此步可略
if($pid!=0){ #条件选择,测试$pid值
print"This is a main pid!PID is $$!\n"; #$pid值不等于0,此为父进程(附:$$为保留变量,其值为此进程的PID)
}else{ #否则.....
print"This is a sub pid!PID is $$!\n"; #$pid值为0,此为子进程
}
exit 1; #退出程序
分析实例:
楼上的程序没有父进程与子进程的明显分化,要将它们分开就要靠测试$pid的值,所以对fork()函数的调用来说条件语句是非常重要的,需要通过它们来辨别fork() 的返回值。
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
getppid()函数:
作用:在子进程中调用此函数来获得父进程PID值。
用法:$parent=getppid();
讲解:无参数,调用后其返回值为父进程的PID值。
实例:
#!usr/bin/perl -w
$pid=fork(); #复制进程
die "Error:$!\n" unless defined $pid; #制定错误机制,此步可略
if($pid==0){ #当进程为子进程则进入条件,当进程为父进程则跳过到程序结束
$parent=getppid(); #通过getppid()得到父进程PID值
print"This is a sub pid:$$,the parent is $parent\n"; #在STDOUT打印子进程PID值与其父进程ID值
}
exit 1; #退出程序
注意:楼上的getppid()实例无法在WIN32下通过,建议使用*nix平台。
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
关于使用fork():通过fork()创建的子进程共享了父进程的所有变量、句柄等当前值。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
system()与exec()部分:更直观的进程调用
=============================================================
system()函数:
作用:直接生成子进程。
用法:$result=system("dir/w *.bat"); 或 $result=system("dir/w","*.bat");
讲解:参数为SHELL语句。当函数能正常调用时返回值为0(注意:此与其他函数不一致),其他返回值均为错误。
实例:
#!usr/bin/perl -w
print STDOUT system("dir/w","*.pl"); #把system()函数中的子进程SHELL语句"dir/w *.pl"的结果输出到STDOUT中
exit 1; #退出程序
#在c:\根目录下运行结果为:
C:\>perl mm.pl
驱动器 C 中的卷没有标签。
卷的序列号是 2629-08EF
C:\ 的目录
aaa.pl bbb.pl zzz.pl xxx.pl SOCK.PL
connect.pl connect2.pl connect3.pl connect4.pl connect5.pl
connect6.pl connect7.pl udpc.pl udps.pl connect8.pl
connect10.pl fork.pl pidd.pl mm.pl
19 个文件 7,503 字节
0 个目录 5,514,014,720 可用字节
0
#注意楼上最后的"0",这就是返回后的数值,楼上表示程序正常调用了system()函数中的shell语句了。
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
exec()函数:
作用:以指定的SHELL语句代替原进程。
用法:$result=exec("copy *.bat c:\"); 或 $result=exec("copy","*.bat","c:\");
讲解:参数为SHELL语句,成功调用后返回值为undef,其他返回值均为失败。使用此函数后生成的新进程与原进程为同一进程,
有相同的PID,共享变量语柄等一切当前值。
实例与system()相当,所以不作讨论了。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
附:关于"Perl的管道"部分内容博大精深,而本人又水平有限,所以只好草草了事,如果有哪里不妥还望各位前辈指点![]()
管道是为了使不同进程可以进行通信的制定的。管道是*NIX编程的重点。
与其相关的函数有:open()、pipe()等等。
open():作打开句柄用。
格式:open(FILEHANDLE,"符号+参数");
例子:open(NIX,"|wc -lw"); #打开名为NIX的管道,其进程为‘wc -lw’,管道为写入。
open(DDD,"dir c:\|"); #打开名为DDD的管道,其进程为‘dir c:\’,管道为读取。
讲解:FILEHANDLE(句柄)包括很多成分,如文件句柄、SOCKET句柄、管道句柄,此文只谈到管道句柄。
第二个参数为双引号或单引号相括着的管道符号与参数。管道符号为"|",把管道符号放到参数的左边为‘只读’,放到右边为‘只写’,如果两边都有便为双向管道(既可读也可写)。
简单的管道实例:
#!usr/bin/perl -w
open(AAA,"dir d:|"); #打开管道AAA,进程为"dir d:",只读
@bbb=<AAA>; #从管道中读取内容,并压入@bbb数组
print"@bbb\n"; #把@bbb数组全部输出到STDOUT
close AAA; #关闭管道AAA
exit 1; #退出程序
〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
pipe():创建管道对。
格式: pipe(READ,WRITE);
实例:pipe(README,WRITEME); #创建了一个管道对,"README"用于读,"WRITEME"用于写。
$aaa=pipe(AAA,BBB); #创建了一个管道对,"AAA"用于读,"BBB"用于写,$aaa变量为调用pipe()的返回值。
讲解:正常调用后返回值为非零数,第一个参数为被创建的读管道,第二个参数为被创建的写管道。此函数通常配合进程中
的fork()函数一同使用,步骤是先使用pipe()函数建立管道对,再使用fork()创建新进程,在不同的进程关闭不同的
管道,这样就可以达到管道间通信的目的了。
〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
close():关闭管道
格式: close(AAA);
close BBB;
实例与格式相当,也就不详细介绍了。
讲解:close()在调用时能将子程序的终止代码放到特殊变量$?中;当关闭的是写管道时close()调用将进入堵塞状态直至另一
端完成它的全部工作为止。
信号其实就是编程里俗称的中断,它使监视与控制其他进程变为有可能。
首先说说通用信号,通用信号归纳起来可以组成以下列表:
=============================================================
信号名 值 标注 解释
------------------------------------------------------------------------
HUP 1 A 检测到挂起
INT 2 A 来自键盘的中断
QUIT 3 A 来自键盘的停止
ILL 4 A 非法指令
ABRT 6 C 失败
FPE 8 C 浮点异常
KILL 9 AF 终端信号
USR1 10 A 用户定义的信号1
SEGV 11 C 非法内存访问
USR2 12 A 用户定义的信号2
PIPE 13 A 写往没有读取者的管道
ALRM 14 A 来自闹钟的定时器信号
TERM 15 A 终端信号
CHLD 17 B 子进程终止
CONT 18 E 如果被停止则继续
STOP 19 DF 停止进程
TSTP 20 D tty键入的停止命令
TTIN 21 D 对后台进程的tty输入
TTOU 22 D 对后台进程的tty输出
------------------------------------------------------------------------
著明:上表中‘值’列下没有列出的值所对应的信号为系统调用的非标准信号,在此
文不予以探讨。上表中的第三列‘标注’定义了当进程接受到信号后的操作,
如:
A-----终止进程
B-----忽略进程信号
C-----终止进程并卸下内核
D-----停止进程
E-----恢复进程
F-----不能截取或忽略进程信号
=============================================================
下面就以INT作范例演示一下调用过程吧:
#!usr/bin/perl -w
#c:\test11.pl
my $aaa=0; #对计数器变量$aaa进行负值
while($aaa<3){ #进入循环体
print"Begin\n"; #打印字符串到STDOUT
sleep(5); #睡眠函数,参数为5秒
next unless $SIG{INT}=\&demon; #选择结构,demon子程序值负于中断函数
}
sub demon{ #demon子程序体
$aaa++; #计数器自加
print"Stop!\n"; #打印字符串到STDOUT
}
exit 1; #退出程序
输出结果:在SHELL里不停的打印出"Begin"字样,相隔5秒,一但在键盘中执行程序
中断操作(Control+"c"),屏幕就会打印出"Stop!"字样,不停地继续下去。
中断调用总结:调用需要使用到系统保留全局HASH数组%SIG,即使用"$SIG{信号名}"
截取信号,截取后将其负某个代码(子函数)的地址值,这代码就是截
取后要执行的结果了。
CONTINUE